parent
a1ce2ac48f
commit
0fc57f2054
@ -0,0 +1,17 @@
|
||||
CFLAGS=-g -I.. -I. -Wall
|
||||
LDLIBS=-lz -ljpeg
|
||||
|
||||
OBJS=cursor.o listen.o rfbproto.o sockets.o vncviewer.o ../libvncserver.a
|
||||
|
||||
all: libvncclient.a
|
||||
|
||||
rfbproto.o: rfbproto.c corre.c hextile.c rre.c tight.c zlib.c
|
||||
|
||||
$(OBJS): ../rfb/rfbclient.h
|
||||
|
||||
libvncclient.a: $(OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
|
||||
|
||||
clean:
|
||||
rm *.o *.a
|
||||
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* corre.c - handle CoRRE encoding.
|
||||
*
|
||||
* This file shouldn't be compiled directly. It is included multiple times by
|
||||
* rfbproto.c, each time with a different definition of the macro BPP. For
|
||||
* each value of BPP, this file defines a function which handles a CoRRE
|
||||
* encoded rectangle with BPP bits per pixel.
|
||||
*/
|
||||
|
||||
#define HandleCoRREBPP CONCAT2E(HandleCoRRE,BPP)
|
||||
#define CARDBPP CONCAT3E(uint,BPP,_t)
|
||||
|
||||
static Bool
|
||||
HandleCoRREBPP (rfbClient* client, int rx, int ry, int rw, int rh)
|
||||
{
|
||||
rfbRREHeader hdr;
|
||||
int i;
|
||||
CARDBPP pix;
|
||||
uint8_t *ptr;
|
||||
int x, y, w, h;
|
||||
|
||||
if (!ReadFromRFBServer(client, (char *)&hdr, sz_rfbRREHeader))
|
||||
return FALSE;
|
||||
|
||||
hdr.nSubrects = Swap32IfLE(hdr.nSubrects);
|
||||
|
||||
if (!ReadFromRFBServer(client, (char *)&pix, sizeof(pix)))
|
||||
return FALSE;
|
||||
|
||||
FillRectangle(client, rx, ry, rw, rh, pix);
|
||||
|
||||
if (!ReadFromRFBServer(client, client->buffer, hdr.nSubrects * (4 + (BPP / 8))))
|
||||
return FALSE;
|
||||
|
||||
ptr = (uint8_t *)client->buffer;
|
||||
|
||||
for (i = 0; i < hdr.nSubrects; i++) {
|
||||
pix = *(CARDBPP *)ptr;
|
||||
ptr += BPP/8;
|
||||
x = *ptr++;
|
||||
y = *ptr++;
|
||||
w = *ptr++;
|
||||
h = *ptr++;
|
||||
|
||||
FillRectangle(client, rx+x, ry+y, w, h, pix);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#undef CARDBPP
|
@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright (C) 2001,2002 Constantin Kaplinsky. All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* cursor.c - code to support cursor shape updates (XCursor and
|
||||
* RichCursor preudo-encodings).
|
||||
*/
|
||||
|
||||
#include <rfb/rfbclient.h>
|
||||
|
||||
|
||||
#define OPER_SAVE 0
|
||||
#define OPER_RESTORE 1
|
||||
|
||||
#define RGB24_TO_PIXEL(bpp,r,g,b) \
|
||||
((((uint##bpp##_t)(r) & 0xFF) * client->format.redMax + 127) / 255 \
|
||||
<< client->format.redShift | \
|
||||
(((uint##bpp##_t)(g) & 0xFF) * client->format.greenMax + 127) / 255 \
|
||||
<< client->format.greenShift | \
|
||||
(((uint##bpp##_t)(b) & 0xFF) * client->format.blueMax + 127) / 255 \
|
||||
<< client->format.blueShift)
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* HandleCursorShape(). Support for XCursor and RichCursor shape
|
||||
* updates. We emulate cursor operating on the frame buffer (that is
|
||||
* why we call it "software cursor").
|
||||
********************************************************************/
|
||||
|
||||
Bool HandleCursorShape(rfbClient* client,int xhot, int yhot, int width, int height, uint32_t enc)
|
||||
{
|
||||
int bytesPerPixel;
|
||||
size_t bytesPerRow, bytesMaskData;
|
||||
rfbXCursorColors rgb;
|
||||
uint32_t colors[2];
|
||||
char *buf;
|
||||
uint8_t *ptr;
|
||||
int x, y, b;
|
||||
|
||||
bytesPerPixel = client->format.bitsPerPixel / 8;
|
||||
bytesPerRow = (width + 7) / 8;
|
||||
bytesMaskData = bytesPerRow * height;
|
||||
|
||||
if (width * height == 0)
|
||||
return TRUE;
|
||||
|
||||
/* Allocate memory for pixel data and temporary mask data. */
|
||||
if(client->rcSource)
|
||||
free(client->rcSource);
|
||||
|
||||
client->rcSource = malloc(width * height * bytesPerPixel);
|
||||
if (client->rcSource == NULL)
|
||||
return FALSE;
|
||||
|
||||
buf = malloc(bytesMaskData);
|
||||
if (buf == NULL) {
|
||||
free(client->rcSource);
|
||||
client->rcSource = NULL;
|
||||
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(client, (char *)&rgb, sz_rfbXCursorColors)) {
|
||||
free(client->rcSource);
|
||||
client->rcSource = NULL;
|
||||
free(buf);
|
||||
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(client, buf, bytesMaskData)) {
|
||||
free(client->rcSource);
|
||||
client->rcSource = NULL;
|
||||
free(buf);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Convert 1bpp data to byte-wide color indices. */
|
||||
ptr = client->rcSource;
|
||||
for (y = 0; y < height; y++) {
|
||||
for (x = 0; x < width / 8; x++) {
|
||||
for (b = 7; b >= 0; b--) {
|
||||
*ptr = buf[y * bytesPerRow + x] >> b & 1;
|
||||
ptr += bytesPerPixel;
|
||||
}
|
||||
}
|
||||
for (b = 7; b > 7 - width % 8; b--) {
|
||||
*ptr = buf[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++)
|
||||
client->rcSource[x] = (uint8_t)colors[client->rcSource[x]];
|
||||
break;
|
||||
case 2:
|
||||
for (x = 0; x < width * height; x++)
|
||||
((uint16_t *)client->rcSource)[x] = (uint16_t)colors[client->rcSource[x * 2]];
|
||||
break;
|
||||
case 4:
|
||||
for (x = 0; x < width * height; x++)
|
||||
((uint32_t *)client->rcSource)[x] = colors[client->rcSource[x * 4]];
|
||||
break;
|
||||
}
|
||||
|
||||
} else { /* enc == rfbEncodingRichCursor */
|
||||
|
||||
if (!ReadFromRFBServer(client, (char *)client->rcSource, width * height * bytesPerPixel)) {
|
||||
free(client->rcSource);
|
||||
client->rcSource = NULL;
|
||||
free(buf);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Read and decode mask data. */
|
||||
|
||||
if (!ReadFromRFBServer(client, buf, bytesMaskData)) {
|
||||
free(client->rcSource);
|
||||
client->rcSource = NULL;
|
||||
free(buf);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
client->rcMask = malloc(width * height);
|
||||
if (client->rcMask == NULL) {
|
||||
free(client->rcSource);
|
||||
client->rcSource = NULL;
|
||||
free(buf);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ptr = client->rcMask;
|
||||
for (y = 0; y < height; y++) {
|
||||
for (x = 0; x < width / 8; x++) {
|
||||
for (b = 7; b >= 0; b--) {
|
||||
*ptr++ = buf[y * bytesPerRow + x] >> b & 1;
|
||||
}
|
||||
}
|
||||
for (b = 7; b > 7 - width % 8; b--) {
|
||||
*ptr++ = buf[y * bytesPerRow + x] >> b & 1;
|
||||
}
|
||||
}
|
||||
|
||||
free(buf);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* hextile.c - handle hextile encoding.
|
||||
*
|
||||
* This file shouldn't be compiled directly. It is included multiple times by
|
||||
* rfbproto.c, each time with a different definition of the macro BPP. For
|
||||
* each value of BPP, this file defines a function which handles a hextile
|
||||
* encoded rectangle with BPP bits per pixel.
|
||||
*/
|
||||
|
||||
#define HandleHextileBPP CONCAT2E(HandleHextile,BPP)
|
||||
#define CARDBPP CONCAT3E(uint,BPP,_t)
|
||||
#define GET_PIXEL CONCAT2E(GET_PIXEL,BPP)
|
||||
|
||||
static Bool
|
||||
HandleHextileBPP (rfbClient* client, int rx, int ry, int rw, int rh)
|
||||
{
|
||||
CARDBPP bg, fg;
|
||||
int i;
|
||||
uint8_t *ptr;
|
||||
int x, y, w, h;
|
||||
int sx, sy, sw, sh;
|
||||
uint8_t subencoding;
|
||||
uint8_t nSubrects;
|
||||
|
||||
for (y = ry; y < ry+rh; y += 16) {
|
||||
for (x = rx; x < rx+rw; x += 16) {
|
||||
w = h = 16;
|
||||
if (rx+rw - x < 16)
|
||||
w = rx+rw - x;
|
||||
if (ry+rh - y < 16)
|
||||
h = ry+rh - y;
|
||||
|
||||
if (!ReadFromRFBServer(client, (char *)&subencoding, 1))
|
||||
return FALSE;
|
||||
|
||||
if (subencoding & rfbHextileRaw) {
|
||||
if (!ReadFromRFBServer(client, client->buffer, w * h * (BPP / 8)))
|
||||
return FALSE;
|
||||
|
||||
CopyRectangle(client, client->buffer, x, y, w, h);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (subencoding & rfbHextileBackgroundSpecified)
|
||||
if (!ReadFromRFBServer(client, (char *)&bg, sizeof(bg)))
|
||||
return FALSE;
|
||||
|
||||
FillRectangle(client, x, y, w, h, fg);
|
||||
|
||||
if (subencoding & rfbHextileForegroundSpecified)
|
||||
if (!ReadFromRFBServer(client, (char *)&fg, sizeof(fg)))
|
||||
return FALSE;
|
||||
|
||||
if (!(subencoding & rfbHextileAnySubrects)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ReadFromRFBServer(client, (char *)&nSubrects, 1))
|
||||
return FALSE;
|
||||
|
||||
ptr = (uint8_t*)client->buffer;
|
||||
|
||||
if (subencoding & rfbHextileSubrectsColoured) {
|
||||
if (!ReadFromRFBServer(client, client->buffer, nSubrects * (2 + (BPP / 8))))
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < nSubrects; i++) {
|
||||
GET_PIXEL(fg, ptr);
|
||||
sx = rfbHextileExtractX(*ptr);
|
||||
sy = rfbHextileExtractY(*ptr);
|
||||
ptr++;
|
||||
sw = rfbHextileExtractW(*ptr);
|
||||
sh = rfbHextileExtractH(*ptr);
|
||||
ptr++;
|
||||
|
||||
FillRectangle(client, x+sx, y+sy, sw, sh, fg);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!ReadFromRFBServer(client, client->buffer, nSubrects * 2))
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < nSubrects; i++) {
|
||||
sx = rfbHextileExtractX(*ptr);
|
||||
sy = rfbHextileExtractY(*ptr);
|
||||
ptr++;
|
||||
sw = rfbHextileExtractW(*ptr);
|
||||
sh = rfbHextileExtractH(*ptr);
|
||||
ptr++;
|
||||
|
||||
FillRectangle(client, x+sx, y+sy, sw, sh, fg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#undef CARDBPP
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* listen.c - listen for incoming connections
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <rfb/rfbclient.h>
|
||||
|
||||
/*
|
||||
* listenForIncomingConnections() - listen for incoming connections from
|
||||
* servers, and fork a new process to deal with each connection.
|
||||
*/
|
||||
|
||||
void
|
||||
listenForIncomingConnections(rfbClient* client)
|
||||
{
|
||||
int listenSocket;
|
||||
fd_set fds;
|
||||
|
||||
client->listenSpecified = TRUE;
|
||||
|
||||
listenSocket = ListenAtTcpPort(client->listenPort);
|
||||
|
||||
if ((listenSocket < 0)) exit(1);
|
||||
|
||||
fprintf(stderr,"%s -listen: Listening on port %d\n",
|
||||
client->programName,client->listenPort);
|
||||
fprintf(stderr,"%s -listen: Command line errors are not reported until "
|
||||
"a connection comes in.\n", client->programName);
|
||||
|
||||
while (TRUE) {
|
||||
|
||||
/* reap any zombies */
|
||||
int status, pid;
|
||||
while ((pid= wait3(&status, WNOHANG, (struct rusage *)0))>0);
|
||||
|
||||
/* TODO: callback for discard any events (like X11 events) */
|
||||
|
||||
FD_ZERO(&fds);
|
||||
|
||||
FD_SET(listenSocket, &fds);
|
||||
|
||||
select(FD_SETSIZE, &fds, NULL, NULL, NULL);
|
||||
|
||||
if (FD_ISSET(listenSocket, &fds)) {
|
||||
client->sock = AcceptTcpConnection(listenSocket);
|
||||
if (client->sock < 0) exit(1);
|
||||
if (!SetNonBlocking(client->sock)) exit(1);
|
||||
|
||||
/* Now fork off a new process to deal with it... */
|
||||
|
||||
switch (fork()) {
|
||||
|
||||
case -1:
|
||||
perror("fork");
|
||||
exit(1);
|
||||
|
||||
case 0:
|
||||
/* child - return to caller */
|
||||
close(listenSocket);
|
||||
return;
|
||||
|
||||
default:
|
||||
/* parent - go round and listen again */
|
||||
close(client->sock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* rre.c - handle RRE encoding.
|
||||
*
|
||||
* This file shouldn't be compiled directly. It is included multiple times by
|
||||
* rfbproto.c, each time with a different definition of the macro BPP. For
|
||||
* each value of BPP, this file defines a function which handles an RRE
|
||||
* encoded rectangle with BPP bits per pixel.
|
||||
*/
|
||||
|
||||
#define HandleRREBPP CONCAT2E(HandleRRE,BPP)
|
||||
#define CARDBPP CONCAT3E(uint,BPP,_t)
|
||||
|
||||
static Bool
|
||||
HandleRREBPP (rfbClient* client, int rx, int ry, int rw, int rh)
|
||||
{
|
||||
rfbRREHeader hdr;
|
||||
int i;
|
||||
CARDBPP pix;
|
||||
rfbRectangle subrect;
|
||||
|
||||
if (!ReadFromRFBServer(client, (char *)&hdr, sz_rfbRREHeader))
|
||||
return FALSE;
|
||||
|
||||
hdr.nSubrects = Swap32IfLE(hdr.nSubrects);
|
||||
|
||||
if (!ReadFromRFBServer(client, (char *)&pix, sizeof(pix)))
|
||||
return FALSE;
|
||||
|
||||
FillRectangle(client, rx, ry, rw, rh, pix);
|
||||
|
||||
for (i = 0; i < hdr.nSubrects; i++) {
|
||||
if (!ReadFromRFBServer(client, (char *)&pix, sizeof(pix)))
|
||||
return FALSE;
|
||||
|
||||
if (!ReadFromRFBServer(client, (char *)&subrect, sz_rfbRectangle))
|
||||
return FALSE;
|
||||
|
||||
subrect.x = Swap16IfLE(subrect.x);
|
||||
subrect.y = Swap16IfLE(subrect.y);
|
||||
subrect.w = Swap16IfLE(subrect.w);
|
||||
subrect.h = Swap16IfLE(subrect.h);
|
||||
|
||||
FillRectangle(client, rx+subrect.x, ry+subrect.y, subrect.w, subrect.h, pix);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#undef CARDBPP
|
@ -0,0 +1,424 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* sockets.c - functions to deal with sockets.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <errno.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
#include <rfb/rfbclient.h>
|
||||
|
||||
void PrintInHex(char *buf, int len);
|
||||
|
||||
Bool errorMessageOnReadFailure = TRUE;
|
||||
|
||||
#define BUF_SIZE 8192
|
||||
static char buf[BUF_SIZE];
|
||||
static char *bufoutptr = buf;
|
||||
static int buffered = 0;
|
||||
|
||||
/*
|
||||
* ReadFromRFBServer is called whenever we want to read some data from the RFB
|
||||
* server. It is non-trivial for two reasons:
|
||||
*
|
||||
* 1. For efficiency it performs some intelligent buffering, avoiding invoking
|
||||
* the read() system call too often. For small chunks of data, it simply
|
||||
* copies the data out of an internal buffer. For large amounts of data it
|
||||
* reads directly into the buffer provided by the caller.
|
||||
*
|
||||
* 2. Whenever read() would block, it invokes the Xt event dispatching
|
||||
* mechanism to process X events. In fact, this is the only place these
|
||||
* events are processed, as there is no XtAppMainLoop in the program.
|
||||
*/
|
||||
|
||||
Bool
|
||||
ReadFromRFBServer(rfbClient* client, char *out, unsigned int n)
|
||||
{
|
||||
if (n <= buffered) {
|
||||
memcpy(out, bufoutptr, n);
|
||||
bufoutptr += n;
|
||||
buffered -= n;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
memcpy(out, bufoutptr, buffered);
|
||||
|
||||
out += buffered;
|
||||
n -= buffered;
|
||||
|
||||
bufoutptr = buf;
|
||||
buffered = 0;
|
||||
|
||||
if (n <= BUF_SIZE) {
|
||||
|
||||
while (buffered < n) {
|
||||
int i = read(client->sock, buf + buffered, BUF_SIZE - buffered);
|
||||
if (i <= 0) {
|
||||
if (i < 0) {
|
||||
if (errno == EWOULDBLOCK || errno == EAGAIN) {
|
||||
/* TODO:
|
||||
ProcessXtEvents();
|
||||
*/
|
||||
i = 0;
|
||||
} else {
|
||||
perror("read");
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
if (errorMessageOnReadFailure) {
|
||||
fprintf(stderr,"VNC server closed connection\n");
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
buffered += i;
|
||||
}
|
||||
|
||||
memcpy(out, bufoutptr, n);
|
||||
bufoutptr += n;
|
||||
buffered -= n;
|
||||
return TRUE;
|
||||
|
||||
} else {
|
||||
|
||||
while (n > 0) {
|
||||
int i = read(client->sock, out, n);
|
||||
if (i <= 0) {
|
||||
if (i < 0) {
|
||||
if (errno == EWOULDBLOCK || errno == EAGAIN) {
|
||||
/* TODO:
|
||||
ProcessXtEvents();
|
||||
*/
|
||||
i = 0;
|
||||
} else {
|
||||
perror("read");
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
if (errorMessageOnReadFailure) {
|
||||
fprintf(stderr,"VNC server closed connection\n");
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
out += i;
|
||||
n -= i;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Write an exact number of bytes, and don't return until you've sent them.
|
||||
*/
|
||||
|
||||
Bool
|
||||
WriteExact(rfbClient* client, char *buf, int n)
|
||||
{
|
||||
fd_set fds;
|
||||
int i = 0;
|
||||
int j;
|
||||
|
||||
while (i < n) {
|
||||
j = write(client->sock, buf + i, (n - i));
|
||||
if (j <= 0) {
|
||||
if (j < 0) {
|
||||
if (errno == EWOULDBLOCK || errno == EAGAIN) {
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(client->sock,&fds);
|
||||
|
||||
if (select(client->sock+1, NULL, &fds, NULL, NULL) <= 0) {
|
||||
perror("select");
|
||||
return FALSE;
|
||||
}
|
||||
j = 0;
|
||||
} else {
|
||||
perror("write");
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr,"write failed\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
i += j;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ConnectToTcpAddr connects to the given TCP port.
|
||||
*/
|
||||
|
||||
int
|
||||
ConnectToTcpAddr(unsigned int host, int port)
|
||||
{
|
||||
int sock;
|
||||
struct sockaddr_in addr;
|
||||
int one = 1;
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
addr.sin_addr.s_addr = host;
|
||||
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock < 0) {
|
||||
perror("ConnectToTcpAddr: socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
perror("ConnectToTcpAddr: connect");
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
|
||||
(char *)&one, sizeof(one)) < 0) {
|
||||
perror("ConnectToTcpAddr: setsockopt");
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* FindFreeTcpPort tries to find unused TCP port in the range
|
||||
* (TUNNEL_PORT_OFFSET, TUNNEL_PORT_OFFSET + 99]. Returns 0 on failure.
|
||||
*/
|
||||
|
||||
int
|
||||
FindFreeTcpPort(void)
|
||||
{
|
||||
int sock, port;
|
||||
struct sockaddr_in addr;
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock < 0) {
|
||||
perror(": FindFreeTcpPort: socket");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (port = TUNNEL_PORT_OFFSET + 99; port > TUNNEL_PORT_OFFSET; port--) {
|
||||
addr.sin_port = htons((unsigned short)port);
|
||||
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
|
||||
close(sock);
|
||||
return port;
|
||||
}
|
||||
}
|
||||
|
||||
close(sock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ListenAtTcpPort starts listening at the given TCP port.
|
||||
*/
|
||||
|
||||
int
|
||||
ListenAtTcpPort(int port)
|
||||
{
|
||||
int sock;
|
||||
struct sockaddr_in addr;
|
||||
int one = 1;
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock < 0) {
|
||||
perror("ListenAtTcpPort: socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
|
||||
(const char *)&one, sizeof(one)) < 0) {
|
||||
perror("ListenAtTcpPort: setsockopt");
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
perror("ListenAtTcpPort: bind");
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen(sock, 5) < 0) {
|
||||
perror("ListenAtTcpPort: listen");
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* AcceptTcpConnection accepts a TCP connection.
|
||||
*/
|
||||
|
||||
int
|
||||
AcceptTcpConnection(int listenSock)
|
||||
{
|
||||
int sock;
|
||||
struct sockaddr_in addr;
|
||||
int addrlen = sizeof(addr);
|
||||
int one = 1;
|
||||
|
||||
sock = accept(listenSock, (struct sockaddr *) &addr, &addrlen);
|
||||
if (sock < 0) {
|
||||
perror("AcceptTcpConnection: accept");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
|
||||
(char *)&one, sizeof(one)) < 0) {
|
||||
perror("AcceptTcpConnection: setsockopt");
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SetNonBlocking sets a socket into non-blocking mode.
|
||||
*/
|
||||
|
||||
Bool
|
||||
SetNonBlocking(int sock)
|
||||
{
|
||||
if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
|
||||
perror("AcceptTcpConnection: fcntl");
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* StringToIPAddr - convert a host string to an IP address.
|
||||
*/
|
||||
|
||||
Bool
|
||||
StringToIPAddr(const char *str, unsigned int *addr)
|
||||
{
|
||||
struct hostent *hp;
|
||||
|
||||
if (strcmp(str,"") == 0) {
|
||||
*addr = 0; /* local */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
*addr = inet_addr(str);
|
||||
|
||||
if (*addr != -1)
|
||||
return TRUE;
|
||||
|
||||
hp = gethostbyname(str);
|
||||
|
||||
if (hp) {
|
||||
*addr = *(unsigned int *)hp->h_addr;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Test if the other end of a socket is on the same machine.
|
||||
*/
|
||||
|
||||
Bool
|
||||
SameMachine(int sock)
|
||||
{
|
||||
struct sockaddr_in peeraddr, myaddr;
|
||||
int addrlen = sizeof(struct sockaddr_in);
|
||||
|
||||
getpeername(sock, (struct sockaddr *)&peeraddr, &addrlen);
|
||||
getsockname(sock, (struct sockaddr *)&myaddr, &addrlen);
|
||||
|
||||
return (peeraddr.sin_addr.s_addr == myaddr.sin_addr.s_addr);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Print out the contents of a packet for debugging.
|
||||
*/
|
||||
|
||||
void
|
||||
PrintInHex(char *buf, int len)
|
||||
{
|
||||
int i, j;
|
||||
char c, str[17];
|
||||
|
||||
str[16] = 0;
|
||||
|
||||
fprintf(stderr,"ReadExact: ");
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
if ((i % 16 == 0) && (i != 0)) {
|
||||
fprintf(stderr," ");
|
||||
}
|
||||
c = buf[i];
|
||||
str[i % 16] = (((c > 31) && (c < 127)) ? c : '.');
|
||||
fprintf(stderr,"%02x ",(unsigned char)c);
|
||||
if ((i % 4) == 3)
|
||||
fprintf(stderr," ");
|
||||
if ((i % 16) == 15)
|
||||
{
|
||||
fprintf(stderr,"%s\n",str);
|
||||
}
|
||||
}
|
||||
if ((i % 16) != 0)
|
||||
{
|
||||
for (j = i % 16; j < 16; j++)
|
||||
{
|
||||
fprintf(stderr," ");
|
||||
if ((j % 4) == 3) fprintf(stderr," ");
|
||||
}
|
||||
str[i % 16] = 0;
|
||||
fprintf(stderr,"%s\n",str);
|
||||
}
|
||||
|
||||
fflush(stderr);
|
||||
}
|
@ -0,0 +1,606 @@
|
||||
/*
|
||||
* Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* tight.c - handle ``tight'' encoding.
|
||||
*
|
||||
* This file shouldn't be compiled directly. It is included multiple
|
||||
* times by rfbproto.c, each time with a different definition of the
|
||||
* macro BPP. For each value of BPP, this file defines a function
|
||||
* which handles a tight-encoded rectangle with BPP bits per pixel.
|
||||
*
|
||||
*/
|
||||
|
||||
#define TIGHT_MIN_TO_COMPRESS 12
|
||||
|
||||
#define CARDBPP CONCAT3E(uint,BPP,_t)
|
||||
#define filterPtrBPP CONCAT2E(filterPtr,BPP)
|
||||
|
||||
#define HandleTightBPP CONCAT2E(HandleTight,BPP)
|
||||
#define InitFilterCopyBPP CONCAT2E(InitFilterCopy,BPP)
|
||||
#define InitFilterPaletteBPP CONCAT2E(InitFilterPalette,BPP)
|
||||
#define InitFilterGradientBPP CONCAT2E(InitFilterGradient,BPP)
|
||||
#define FilterCopyBPP CONCAT2E(FilterCopy,BPP)
|
||||
#define FilterPaletteBPP CONCAT2E(FilterPalette,BPP)
|
||||
#define FilterGradientBPP CONCAT2E(FilterGradient,BPP)
|
||||
|
||||
#if BPP != 8
|
||||
#define DecompressJpegRectBPP CONCAT2E(DecompressJpegRect,BPP)
|
||||
#endif
|
||||
|
||||
#ifndef RGB_TO_PIXEL
|
||||
|
||||
#define RGB_TO_PIXEL(bpp,r,g,b) \
|
||||
(((CARD##bpp)(r) & client->format.redMax) << client->format.redShift | \
|
||||
((CARD##bpp)(g) & client->format.greenMax) << client->format.greenShift | \
|
||||
((CARD##bpp)(b) & client->format.blueMax) << client->format.blueShift)
|
||||
|
||||
#define RGB24_TO_PIXEL(bpp,r,g,b) \
|
||||
((((CARD##bpp)(r) & 0xFF) * client->format.redMax + 127) / 255 \
|
||||
<< client->format.redShift | \
|
||||
(((CARD##bpp)(g) & 0xFF) * client->format.greenMax + 127) / 255 \
|
||||
<< client->format.greenShift | \
|
||||
(((CARD##bpp)(b) & 0xFF) * client->format.blueMax + 127) / 255 \
|
||||
<< client->format.blueShift)
|
||||
|
||||
#define RGB24_TO_PIXEL32(r,g,b) \
|
||||
(((uint32_t)(r) & 0xFF) << client->format.redShift | \
|
||||
((uint32_t)(g) & 0xFF) << client->format.greenShift | \
|
||||
((uint32_t)(b) & 0xFF) << client->format.blueShift)
|
||||
|
||||
#endif
|
||||
|
||||
/* Type declarations */
|
||||
|
||||
typedef void (*filterPtrBPP)(rfbClient* client, int, CARDBPP *);
|
||||
|
||||
/* Prototypes */
|
||||
|
||||
static int InitFilterCopyBPP (rfbClient* client, int rw, int rh);
|
||||
static int InitFilterPaletteBPP (rfbClient* client, int rw, int rh);
|
||||
static int InitFilterGradientBPP (rfbClient* client, int rw, int rh);
|
||||
static void FilterCopyBPP (rfbClient* client, int numRows, CARDBPP *destBuffer);
|
||||
static void FilterPaletteBPP (rfbClient* client, int numRows, CARDBPP *destBuffer);
|
||||
static void FilterGradientBPP (rfbClient* client, int numRows, CARDBPP *destBuffer);
|
||||
|
||||
#if BPP != 8
|
||||
static Bool DecompressJpegRectBPP(rfbClient* client, int x, int y, int w, int h);
|
||||
#endif
|
||||
|
||||
/* Definitions */
|
||||
|
||||
static Bool
|
||||
HandleTightBPP (rfbClient* client, int rx, int ry, int rw, int rh)
|
||||
{
|
||||
CARDBPP fill_colour;
|
||||
uint8_t comp_ctl;
|
||||
uint8_t filter_id;
|
||||
filterPtrBPP filterFn;
|
||||
z_streamp zs;
|
||||
char *buffer2;
|
||||
int err, stream_id, compressedLen, bitsPixel;
|
||||
int bufferSize, rowSize, numRows, portionLen, rowsProcessed, extraBytes;
|
||||
|
||||
if (!ReadFromRFBServer(client, (char *)&comp_ctl, 1))
|
||||
return FALSE;
|
||||
|
||||
/* Flush zlib streams if we are told by the server to do so. */
|
||||
for (stream_id = 0; stream_id < 4; stream_id++) {
|
||||
if ((comp_ctl & 1) && zlibStreamActive[stream_id]) {
|
||||
if (inflateEnd (&zlibStream[stream_id]) != Z_OK &&
|
||||
zlibStream[stream_id].msg != NULL)
|
||||
fprintf(stderr, "inflateEnd: %s\n", zlibStream[stream_id].msg);
|
||||
zlibStreamActive[stream_id] = FALSE;
|
||||
}
|
||||
comp_ctl >>= 1;
|
||||
}
|
||||
|
||||
/* Handle solid rectangles. */
|
||||
if (comp_ctl == rfbTightFill) {
|
||||
#if BPP == 32
|
||||
if (client->format.depth == 24 && client->format.redMax == 0xFF &&
|
||||
client->format.greenMax == 0xFF && client->format.blueMax == 0xFF) {
|
||||
if (!ReadFromRFBServer(client, client->buffer, 3))
|
||||
return FALSE;
|
||||
fill_colour = RGB24_TO_PIXEL32(client->buffer[0], client->buffer[1], client->buffer[2]);
|
||||
} else {
|
||||
if (!ReadFromRFBServer(client, (char*)&fill_colour, sizeof(fill_colour)))
|
||||
return FALSE;
|
||||
}
|
||||
#else
|
||||
if (!ReadFromRFBServer(client, (char*)&fill_colour, sizeof(fill_colour)))
|
||||
return FALSE;
|
||||
#endif
|
||||
|
||||
FillRectangle(client, rx, ry, rw, rh, fill_colour);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#if BPP == 8
|
||||
if (comp_ctl == rfbTightJpeg) {
|
||||
fprintf(stderr, "Tight encoding: JPEG is not supported in 8 bpp mode.\n");
|
||||
return FALSE;
|
||||
}
|
||||
#else
|
||||
if (comp_ctl == rfbTightJpeg) {
|
||||
return DecompressJpegRectBPP(client, rx, ry, rw, rh);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Quit on unsupported subencoding value. */
|
||||
if (comp_ctl > rfbTightMaxSubencoding) {
|
||||
fprintf(stderr, "Tight encoding: bad subencoding value received.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Here primary compression mode handling begins.
|
||||
* Data was processed with optional filter + zlib compression.
|
||||
*/
|
||||
|
||||
/* First, we should identify a filter to use. */
|
||||
if ((comp_ctl & rfbTightExplicitFilter) != 0) {
|
||||
if (!ReadFromRFBServer(client, (char*)&filter_id, 1))
|
||||
return FALSE;
|
||||
|
||||
switch (filter_id) {
|
||||
case rfbTightFilterCopy:
|
||||
filterFn = FilterCopyBPP;
|
||||
bitsPixel = InitFilterCopyBPP(client, rw, rh);
|
||||
break;
|
||||
case rfbTightFilterPalette:
|
||||
filterFn = FilterPaletteBPP;
|
||||
bitsPixel = InitFilterPaletteBPP(client, rw, rh);
|
||||
break;
|
||||
case rfbTightFilterGradient:
|
||||
filterFn = FilterGradientBPP;
|
||||
bitsPixel = InitFilterGradientBPP(client, rw, rh);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Tight encoding: unknown filter code received.\n");
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
filterFn = FilterCopyBPP;
|
||||
bitsPixel = InitFilterCopyBPP(client, rw, rh);
|
||||
}
|
||||
if (bitsPixel == 0) {
|
||||
fprintf(stderr, "Tight encoding: error receiving palette.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Determine if the data should be decompressed or just copied. */
|
||||
rowSize = (rw * bitsPixel + 7) / 8;
|
||||
if (rh * rowSize < TIGHT_MIN_TO_COMPRESS) {
|
||||
if (!ReadFromRFBServer(client, (char*)client->buffer, rh * rowSize))
|
||||
return FALSE;
|
||||
|
||||
buffer2 = &client->buffer[TIGHT_MIN_TO_COMPRESS * 4];
|
||||
filterFn(client, rh, (CARDBPP *)buffer2);
|
||||
|
||||
CopyRectangle(client, buffer2, rx, ry, rw, rh);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Read the length (1..3 bytes) of compressed data following. */
|
||||
compressedLen = (int)ReadCompactLen(client);
|
||||
if (compressedLen <= 0) {
|
||||
fprintf(stderr, "Incorrect data received from the server.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Now let's initialize compression stream if needed. */
|
||||
stream_id = comp_ctl & 0x03;
|
||||
zs = &zlibStream[stream_id];
|
||||
if (!zlibStreamActive[stream_id]) {
|
||||
zs->zalloc = Z_NULL;
|
||||
zs->zfree = Z_NULL;
|
||||
zs->opaque = Z_NULL;
|
||||
err = inflateInit(zs);
|
||||
if (err != Z_OK) {
|
||||
if (zs->msg != NULL)
|
||||
fprintf(stderr, "InflateInit error: %s.\n", zs->msg);
|
||||
return FALSE;
|
||||
}
|
||||
zlibStreamActive[stream_id] = TRUE;
|
||||
}
|
||||
|
||||
/* Read, decode and draw actual pixel data in a loop. */
|
||||
|
||||
bufferSize = BUFFER_SIZE * bitsPixel / (bitsPixel + BPP) & 0xFFFFFFFC;
|
||||
buffer2 = &client->buffer[bufferSize];
|
||||
if (rowSize > bufferSize) {
|
||||
/* Should be impossible when BUFFER_SIZE >= 16384 */
|
||||
fprintf(stderr, "Internal error: incorrect buffer size.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
rowsProcessed = 0;
|
||||
extraBytes = 0;
|
||||
|
||||
while (compressedLen > 0) {
|
||||
if (compressedLen > ZLIB_BUFFER_SIZE)
|
||||
portionLen = ZLIB_BUFFER_SIZE;
|
||||
else
|
||||
portionLen = compressedLen;
|
||||
|
||||
if (!ReadFromRFBServer(client, (char*)zlib_buffer, portionLen))
|
||||
return FALSE;
|
||||
|
||||
compressedLen -= portionLen;
|
||||
|
||||
zs->next_in = (Bytef *)zlib_buffer;
|
||||
zs->avail_in = portionLen;
|
||||
|
||||
do {
|
||||
zs->next_out = (Bytef *)&client->buffer[extraBytes];
|
||||
zs->avail_out = bufferSize - extraBytes;
|
||||
|
||||
err = inflate(zs, Z_SYNC_FLUSH);
|
||||
if (err == Z_BUF_ERROR) /* Input exhausted -- no problem. */
|
||||
break;
|
||||
if (err != Z_OK && err != Z_STREAM_END) {
|
||||
if (zs->msg != NULL) {
|
||||
fprintf(stderr, "Inflate error: %s.\n", zs->msg);
|
||||
} else {
|
||||
fprintf(stderr, "Inflate error: %d.\n", err);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
numRows = (bufferSize - zs->avail_out) / rowSize;
|
||||
|
||||
filterFn(client, numRows, (CARDBPP *)buffer2);
|
||||
|
||||
extraBytes = bufferSize - zs->avail_out - numRows * rowSize;
|
||||
if (extraBytes > 0)
|
||||
memcpy(client->buffer, &client->buffer[numRows * rowSize], extraBytes);
|
||||
|
||||
CopyRectangle(client, buffer2, rx, ry+rowsProcessed, rw, numRows);
|
||||
|
||||
rowsProcessed += numRows;
|
||||
}
|
||||
while (zs->avail_out == 0);
|
||||
}
|
||||
|
||||
if (rowsProcessed != rh) {
|
||||
fprintf(stderr, "Incorrect number of scan lines after decompression.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*
|
||||
* Filter stuff.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
The following variables are defined in rfbproto.c:
|
||||
static Bool cutZeros;
|
||||
static int rectWidth, rectColors;
|
||||
static uint8_t tightPalette[256*4];
|
||||
static uint8_t tightPrevRow[2048*3*sizeof(CARD16)];
|
||||
*/
|
||||
|
||||
static int
|
||||
InitFilterCopyBPP (rfbClient* client, int rw, int rh)
|
||||
{
|
||||
rectWidth = rw;
|
||||
|
||||
#if BPP == 32
|
||||
if (client->format.depth == 24 && client->format.redMax == 0xFF &&
|
||||
client->format.greenMax == 0xFF && client->format.blueMax == 0xFF) {
|
||||
cutZeros = TRUE;
|
||||
return 24;
|
||||
} else {
|
||||
cutZeros = FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
return BPP;
|
||||
}
|
||||
|
||||
static void
|
||||
FilterCopyBPP (rfbClient* client, int numRows, CARDBPP *dst)
|
||||
{
|
||||
|
||||
#if BPP == 32
|
||||
int x, y;
|
||||
|
||||
if (cutZeros) {
|
||||
for (y = 0; y < numRows; y++) {
|
||||
for (x = 0; x < rectWidth; x++) {
|
||||
dst[y*rectWidth+x] =
|
||||
RGB24_TO_PIXEL32(client->buffer[(y*rectWidth+x)*3],
|
||||
client->buffer[(y*rectWidth+x)*3+1],
|
||||
client->buffer[(y*rectWidth+x)*3+2]);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
memcpy (dst, client->buffer, numRows * rectWidth * (BPP / 8));
|
||||
}
|
||||
|
||||
static int
|
||||
InitFilterGradientBPP (rfbClient* client, int rw, int rh)
|
||||
{
|
||||
int bits;
|
||||
|
||||
bits = InitFilterCopyBPP(client, rw, rh);
|
||||
if (cutZeros)
|
||||
memset(tightPrevRow, 0, rw * 3);
|
||||
else
|
||||
memset(tightPrevRow, 0, rw * 3 * sizeof(uint16_t));
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
#if BPP == 32
|
||||
|
||||
static void
|
||||
FilterGradient24 (rfbClient* client, int numRows, uint32_t *dst)
|
||||
{
|
||||
int x, y, c;
|
||||
uint8_t thisRow[2048*3];
|
||||
uint8_t pix[3];
|
||||
int est[3];
|
||||
|
||||
for (y = 0; y < numRows; y++) {
|
||||
|
||||
/* First pixel in a row */
|
||||
for (c = 0; c < 3; c++) {
|
||||
pix[c] = tightPrevRow[c] + client->buffer[y*rectWidth*3+c];
|
||||
thisRow[c] = pix[c];
|
||||
}
|
||||
dst[y*rectWidth] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]);
|
||||
|
||||
/* Remaining pixels of a row */
|
||||
for (x = 1; x < rectWidth; x++) {
|
||||
for (c = 0; c < 3; c++) {
|
||||
est[c] = (int)tightPrevRow[x*3+c] + (int)pix[c] -
|
||||
(int)tightPrevRow[(x-1)*3+c];
|
||||
if (est[c] > 0xFF) {
|
||||
est[c] = 0xFF;
|
||||
} else if (est[c] < 0x00) {
|
||||
est[c] = 0x00;
|
||||
}
|
||||
pix[c] = (uint8_t)est[c] + client->buffer[(y*rectWidth+x)*3+c];
|
||||
thisRow[x*3+c] = pix[c];
|
||||
}
|
||||
dst[y*rectWidth+x] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]);
|
||||
}
|
||||
|
||||
memcpy(tightPrevRow, thisRow, rectWidth * 3);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void
|
||||
FilterGradientBPP (rfbClient* client, int numRows, CARDBPP *dst)
|
||||
{
|
||||
int x, y, c;
|
||||
CARDBPP *src = (CARDBPP *)client->buffer;
|
||||
uint16_t *thatRow = (uint16_t *)tightPrevRow;
|
||||
uint16_t thisRow[2048*3];
|
||||
uint16_t pix[3];
|
||||
uint16_t max[3];
|
||||
int shift[3];
|
||||
int est[3];
|
||||
|
||||
#if BPP == 32
|
||||
if (cutZeros) {
|
||||
FilterGradient24(client, numRows, dst);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
max[0] = client->format.redMax;
|
||||
max[1] = client->format.greenMax;
|
||||
max[2] = client->format.blueMax;
|
||||
|
||||
shift[0] = client->format.redShift;
|
||||
shift[1] = client->format.greenShift;
|
||||
shift[2] = client->format.blueShift;
|
||||
|
||||
for (y = 0; y < numRows; y++) {
|
||||
|
||||
/* First pixel in a row */
|
||||
for (c = 0; c < 3; c++) {
|
||||
pix[c] = (uint16_t)(((src[y*rectWidth] >> shift[c]) + thatRow[c]) & max[c]);
|
||||
thisRow[c] = pix[c];
|
||||
}
|
||||
dst[y*rectWidth] = RGB_TO_PIXEL(BPP, pix[0], pix[1], pix[2]);
|
||||
|
||||
/* Remaining pixels of a row */
|
||||
for (x = 1; x < rectWidth; x++) {
|
||||
for (c = 0; c < 3; c++) {
|
||||
est[c] = (int)thatRow[x*3+c] + (int)pix[c] - (int)thatRow[(x-1)*3+c];
|
||||
if (est[c] > (int)max[c]) {
|
||||
est[c] = (int)max[c];
|
||||
} else if (est[c] < 0) {
|
||||
est[c] = 0;
|
||||
}
|
||||
pix[c] = (uint16_t)(((src[y*rectWidth+x] >> shift[c]) + est[c]) & max[c]);
|
||||
thisRow[x*3+c] = pix[c];
|
||||
}
|
||||
dst[y*rectWidth+x] = RGB_TO_PIXEL(BPP, pix[0], pix[1], pix[2]);
|
||||
}
|
||||
memcpy(thatRow, thisRow, rectWidth * 3 * sizeof(uint16_t));
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
InitFilterPaletteBPP (rfbClient* client, int rw, int rh)
|
||||
{
|
||||
uint8_t numColors;
|
||||
#if BPP == 32
|
||||
int i;
|
||||
CARDBPP *palette = (CARDBPP *)tightPalette;
|
||||
#endif
|
||||
|
||||
rectWidth = rw;
|
||||
|
||||
if (!ReadFromRFBServer(client, (char*)&numColors, 1))
|
||||
return 0;
|
||||
|
||||
rectColors = (int)numColors;
|
||||
if (++rectColors < 2)
|
||||
return 0;
|
||||
|
||||
#if BPP == 32
|
||||
if (client->format.depth == 24 && client->format.redMax == 0xFF &&
|
||||
client->format.greenMax == 0xFF && client->format.blueMax == 0xFF) {
|
||||
if (!ReadFromRFBServer(client, (char*)&tightPalette, rectColors * 3))
|
||||
return 0;
|
||||
for (i = rectColors - 1; i >= 0; i--) {
|
||||
palette[i] = RGB24_TO_PIXEL32(tightPalette[i*3],
|
||||
tightPalette[i*3+1],
|
||||
tightPalette[i*3+2]);
|
||||
}
|
||||
return (rectColors == 2) ? 1 : 8;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!ReadFromRFBServer(client, (char*)&tightPalette, rectColors * (BPP / 8)))
|
||||
return 0;
|
||||
|
||||
|