Miscellaneous updates: implemented some more protocol features including
colour maps. Started on a new bitmap decompression engine which is not completely working yet - however I am going back on the road so I am committing now. git-svn-id: svn://svn.code.sf.net/p/rdesktop/code/trunk/rdesktop@6 423420c4-83ab-492f-b58f-81f9feb106b5
This commit is contained in:
parent
72da43c808
commit
26d316fec0
4
Makefile
4
Makefile
@ -5,9 +5,9 @@
|
||||
##############################################
|
||||
|
||||
CC = gcc
|
||||
CFLAGS = -g -Wall
|
||||
CFLAGS = -g -Wall -DDEBUG
|
||||
LIBS = -L/usr/X11R6/lib -lX11
|
||||
OBJECTS = client.o parse.o tcp.o iso.o mcs.o rdp.o bitmap.o xwin.o
|
||||
OBJECTS = client.o parse.o tcp.o iso.o mcs.o rdp.o bitmap.o xwin.o misc.o
|
||||
|
||||
rdesktop: $(OBJECTS)
|
||||
@$(CC) $(CFLAGS) -o rdesktop $(LIBS) $(OBJECTS)
|
||||
|
364
bitmap.c
364
bitmap.c
@ -19,245 +19,175 @@
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include <fcntl.h>
|
||||
|
||||
#define BITMAP_DEBUG 1
|
||||
#define CVAL(p) (*(p++))
|
||||
#define SVAL(p) ((*((p++) + 1) << 8) | CVAL(p))
|
||||
|
||||
#if BITMAP_DEBUG
|
||||
void hexdump(char *filename, unsigned char *data, int length);
|
||||
#endif
|
||||
#define REPEAT(statement) { while ((count > 0) && (x < width)) { statement; count--; x++; } }
|
||||
#define MASK_UPDATE() { maskpix <<= 1; if (maskpix == 0) { mask = CVAL(input); maskpix = 1; } }
|
||||
|
||||
#define RCVAL() (*(input++))
|
||||
#define RSVAL() ((*((input++) + 1) << 8) | RCVAL())
|
||||
#define SCVAL(v) {*(output++) = (v);}
|
||||
|
||||
#define FILL() {while (n-- > 0) { if (output - start < width) { SCVAL(0) } else { SCVAL(*(output-width)); }}}
|
||||
#define MIX() {while (n-- > 0) { if (output - start < width) { SCVAL(mix) } else { SCVAL(*(output-width) ^ mix); }}}
|
||||
#define COPY() {while (n-- > 0) { SCVAL(RCVAL()); }}
|
||||
#define COLOR() {int color = RCVAL(); \
|
||||
while (n-- > 0) { SCVAL(color); }}
|
||||
#define BICOLOR() {int color1 = RCVAL(); int color2 = RCVAL(); \
|
||||
while (n-- > 0) { SCVAL(color1); SCVAL(color2); }}
|
||||
#define SETMIX_MIX() {mix = RCVAL(); MIX();}
|
||||
#define COPY_PACKED() {n++; n/=2; while (n-- > 0) \
|
||||
{unsigned char c = RCVAL(); SCVAL((c & 0xF0) >> 4); \
|
||||
SCVAL(c & 0x0F); }}
|
||||
|
||||
BOOL bitmap_decompress(unsigned char *input, int size,
|
||||
unsigned char *output, int width)
|
||||
BOOL bitmap_decompress(unsigned char *output, int width, int height,
|
||||
unsigned char *input, int size)
|
||||
{
|
||||
unsigned char *savedinput = input;
|
||||
unsigned char *start = output;
|
||||
unsigned char *end = input + size;
|
||||
unsigned char code;
|
||||
unsigned char mix = 0xFF;
|
||||
int n, savedn;
|
||||
unsigned char *prevline, *line = NULL;
|
||||
int opcode, count, offset, isfillormix, x = width;
|
||||
uint8 code, mask, maskpix, color1, color2;
|
||||
uint8 mix = 0xff;
|
||||
|
||||
dump_data(input, end-input);
|
||||
while (input < end)
|
||||
{
|
||||
code = RCVAL();
|
||||
switch (code)
|
||||
{
|
||||
case 0x00: // Fill
|
||||
n = RCVAL() + 32;
|
||||
FILL();
|
||||
break;
|
||||
case 0xF0: // Fill
|
||||
n = RSVAL();
|
||||
FILL();
|
||||
break;
|
||||
case 0x20: // Mix
|
||||
n = RCVAL() + 32;
|
||||
MIX();
|
||||
break;
|
||||
case 0xF1: // Mix
|
||||
n = RSVAL();
|
||||
MIX();
|
||||
break;
|
||||
case 0x40: // FillOrMix
|
||||
fprintf(stderr, "FillOrMix unsupported\n");
|
||||
savedn = n = RCVAL() + 1;
|
||||
MIX();
|
||||
input += (savedn+7)/8;
|
||||
break;
|
||||
case 0xF2:
|
||||
fprintf(stderr, "FillOrMix unsupported\n");
|
||||
savedn = n = RSVAL();
|
||||
MIX();
|
||||
input += (savedn+7)/8;
|
||||
break;
|
||||
case 0x60: // Color
|
||||
n = RCVAL() + 32;
|
||||
COLOR();
|
||||
break;
|
||||
case 0xF3:
|
||||
n = RSVAL();
|
||||
fprintf(stderr, "Color %d\n", n);
|
||||
COLOR();
|
||||
break;
|
||||
case 0x80: // Copy
|
||||
n = RCVAL() + 32;
|
||||
COPY();
|
||||
break;
|
||||
case 0xF4:
|
||||
n = RSVAL();
|
||||
COPY();
|
||||
break;
|
||||
case 0xA0: // Copy Packed
|
||||
fprintf(stderr, "CopyPacked 1\n");
|
||||
n = RCVAL() + 32;
|
||||
COPY_PACKED();
|
||||
break;
|
||||
case 0xF5:
|
||||
fprintf(stderr, "CopyPacked 2\n");
|
||||
n = RSVAL();
|
||||
COPY_PACKED();
|
||||
break;
|
||||
case 0xC0: // SetMix_Mix
|
||||
fprintf(stderr, "SetMix_Mix 1\n");
|
||||
n = RCVAL() + 16;
|
||||
SETMIX_MIX();
|
||||
break;
|
||||
case 0xF6:
|
||||
fprintf(stderr, "SetMix_Mix 2\n");
|
||||
n = RSVAL();
|
||||
SETMIX_MIX();
|
||||
break;
|
||||
case 0xD0: // SetMix_FillOrMix
|
||||
fprintf(stderr, "SetMix_FillOrMix unsupported\n");
|
||||
savedn = n = RCVAL() + 1;
|
||||
SETMIX_MIX();
|
||||
input += (savedn+7)/8;
|
||||
break;
|
||||
case 0xF7:
|
||||
fprintf(stderr, "SetMix_FillOrMix unsupported\n");
|
||||
savedn = n = RSVAL();
|
||||
SETMIX_MIX();
|
||||
input += (savedn+7)/8;
|
||||
break;
|
||||
case 0xE0: // Bicolor
|
||||
fprintf(stderr, "Bicolor 1\n");
|
||||
n = RCVAL() + 16;
|
||||
BICOLOR();
|
||||
break;
|
||||
case 0xF8:
|
||||
fprintf(stderr, "Bicolor 2\n");
|
||||
n = RSVAL();
|
||||
BICOLOR();
|
||||
break;
|
||||
case 0xF9: // FillOrMix_1
|
||||
fprintf(stderr, "FillOrMix_1 unsupported\n");
|
||||
return False;
|
||||
case 0xFA: // FillOrMix_2
|
||||
fprintf(stderr, "FillOrMix_2 unsupported\n");
|
||||
return False;
|
||||
case 0xFD: // White
|
||||
SCVAL(0xFF);
|
||||
break;
|
||||
case 0xFE: // Black
|
||||
SCVAL(0);
|
||||
break;
|
||||
default:
|
||||
n = code & 31;
|
||||
fprintf(stderr, "Offset %d from end\n", end-input);
|
||||
code = CVAL(input);
|
||||
opcode = code >> 4;
|
||||
|
||||
if (n == 0)
|
||||
/* Handle different opcode forms */
|
||||
switch (opcode)
|
||||
{
|
||||
case 0xc:
|
||||
case 0xd:
|
||||
case 0xe:
|
||||
opcode -= 6;
|
||||
count = code & 0xf;
|
||||
offset = 16;
|
||||
break;
|
||||
|
||||
case 0xf:
|
||||
opcode = code & 0xf;
|
||||
count = (opcode < 13) ? SVAL(input) : 1;
|
||||
offset = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
opcode >>= 1;
|
||||
count = code & 0x1f;
|
||||
offset = 32;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Handle strange cases for counts */
|
||||
if (offset != 0)
|
||||
{
|
||||
isfillormix = ((opcode == 2) || (opcode == 7));
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
fprintf(stderr, "Undefined escape 0x%X\n", code);
|
||||
return False;
|
||||
if (isfillormix)
|
||||
count = CVAL(input) + 1;
|
||||
else
|
||||
count = CVAL(input) + offset;
|
||||
}
|
||||
else if (isfillormix)
|
||||
{
|
||||
count <<= 3;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read preliminary data */
|
||||
maskpix = 0;
|
||||
switch (opcode)
|
||||
{
|
||||
case 3: /* Color */
|
||||
color1 = CVAL(input);
|
||||
case 8: /* Bicolor */
|
||||
color2 = CVAL(input);
|
||||
break;
|
||||
case 6: /* SetMix/Mix */
|
||||
case 7: /* SetMix/FillOrMix */
|
||||
mix = CVAL(input);
|
||||
opcode -= 5;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Output body */
|
||||
while (count > 0)
|
||||
{
|
||||
if (x >= width)
|
||||
{
|
||||
if (height <= 0)
|
||||
return True;
|
||||
|
||||
x = 0;
|
||||
height--;
|
||||
|
||||
prevline = line;
|
||||
line = output + height * width;
|
||||
}
|
||||
|
||||
switch ((code >> 5) & 7)
|
||||
switch (opcode)
|
||||
{
|
||||
case 0: // Fill
|
||||
FILL();
|
||||
break;
|
||||
case 1: // Mix
|
||||
MIX();
|
||||
break;
|
||||
case 2: // FillOrMix
|
||||
fprintf(stderr, "FillOrMix unsupported\n");
|
||||
n *= 8;
|
||||
savedn = n;
|
||||
MIX();
|
||||
input += (savedn+7)/8;
|
||||
break;
|
||||
case 3: // Color
|
||||
COLOR();
|
||||
break;
|
||||
case 4: // Copy
|
||||
COPY();
|
||||
break;
|
||||
case 5: // Copy Packed
|
||||
fprintf(stderr, "CopyPacked 3\n");
|
||||
COPY_PACKED();
|
||||
break;
|
||||
case 6:
|
||||
n = code & 15;
|
||||
case 0: /* Fill */
|
||||
fprintf(stderr, "Fill %d\n", count);
|
||||
if (prevline == NULL)
|
||||
REPEAT(line[x] = 0)
|
||||
else
|
||||
REPEAT(line[x] = prevline[x])
|
||||
break;
|
||||
|
||||
switch ((code >> 4) & 15)
|
||||
{
|
||||
case 0xC:
|
||||
fprintf(stderr, "SetMix_Mix 3\n");
|
||||
SETMIX_MIX();
|
||||
case 1: /* Mix */
|
||||
fprintf(stderr, "Mix %d\n", count);
|
||||
if (prevline == NULL)
|
||||
REPEAT(line[x] = mix)
|
||||
else
|
||||
REPEAT(line[x] = prevline[x] ^ mix)
|
||||
break;
|
||||
case 0xD:
|
||||
fprintf(stderr, "SetMix_FillOrMix unsupported\n");
|
||||
n *= 8;
|
||||
savedn = n;
|
||||
SETMIX_MIX();
|
||||
input += (savedn+7)/8;
|
||||
|
||||
#if 0
|
||||
case 2: /* Fill or Mix */
|
||||
REPEAT(line[x] = 0);
|
||||
break;
|
||||
case 0xE:
|
||||
fprintf(stderr, "Bicolor 3\n");
|
||||
BICOLOR();
|
||||
if (prevline == NULL)
|
||||
REPEAT(
|
||||
MASK_UPDATE();
|
||||
|
||||
if (mask & maskpix)
|
||||
line[x] = mix;
|
||||
else
|
||||
line[x] = 0;
|
||||
)
|
||||
else
|
||||
REPEAT(
|
||||
MASK_UPDATE();
|
||||
|
||||
if (mask & maskpix)
|
||||
line[x] = prevline[x] ^ mix;
|
||||
else
|
||||
line[x] = prevline[x];
|
||||
)
|
||||
break;
|
||||
#endif
|
||||
|
||||
case 3: /* Colour */
|
||||
fprintf(stderr, "Colour %d\n", count);
|
||||
REPEAT(line[x] = color2)
|
||||
break;
|
||||
|
||||
case 4: /* Copy */
|
||||
fprintf(stderr, "Copy %d\n", count);
|
||||
REPEAT(line[x] = CVAL(input))
|
||||
break;
|
||||
|
||||
#if 0
|
||||
case 8: /* Bicolor */
|
||||
REPEAT(line[x] = color1; line[++x] = color2)
|
||||
break;
|
||||
|
||||
case 13: /* White */
|
||||
REPEAT(line[x] = 0xff)
|
||||
break;
|
||||
|
||||
case 14: /* Black */
|
||||
REPEAT(line[x] = 0x00)
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
fprintf(stderr, "Undefined escape 0x%X\n", code);
|
||||
fprintf(stderr, "Unknown bitmap opcode 0x%x\n", opcode);
|
||||
return False;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("Uncompressed size: %d\n", output - start);
|
||||
#if BITMAP_DEBUG
|
||||
{
|
||||
static int bmpno = 1;
|
||||
char filename[64];
|
||||
|
||||
snprintf(filename, sizeof(filename)-1, "in%d.raw", bmpno);
|
||||
hexdump(filename, savedinput, size);
|
||||
|
||||
snprintf(filename, sizeof(filename)-1, "out%d.raw", bmpno);
|
||||
hexdump(filename, start, output-start);
|
||||
|
||||
bmpno++;
|
||||
}
|
||||
#endif
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
#if BITMAP_DEBUG
|
||||
void hexdump(char *filename, unsigned char *data, int length)
|
||||
{
|
||||
/*
|
||||
int i;
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
printf("%02X ", data[i]);
|
||||
|
||||
if (i % 16 == 15)
|
||||
printf("\n");
|
||||
}
|
||||
*/
|
||||
|
||||
int fd;
|
||||
|
||||
fd = open(filename, O_WRONLY|O_CREAT, 0600);
|
||||
write(fd, data, length);
|
||||
close(fd);
|
||||
}
|
||||
#endif
|
||||
|
21
client.c
21
client.c
@ -19,7 +19,6 @@
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "signal.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
@ -47,23 +46,3 @@ int main(int argc, char *argv[])
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *xmalloc(int size)
|
||||
{
|
||||
void *mem = malloc(size);
|
||||
if (mem == NULL) {
|
||||
fprintf(stderr, "xmalloc: Out of memory.\n");
|
||||
exit(1);
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
||||
void *xrealloc(void *oldmem, int size)
|
||||
{
|
||||
void *mem = realloc(oldmem, size);
|
||||
if (mem == NULL) {
|
||||
fprintf(stderr, "xrealloc: Out of memory.\n");
|
||||
exit(1);
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ typedef unsigned short uint16;
|
||||
typedef unsigned int uint32;
|
||||
|
||||
#include "xwin.h"
|
||||
#include "misc.h"
|
||||
#include "parse.h"
|
||||
#include "tcp.h"
|
||||
#include "iso.h"
|
||||
|
39
mcs.c
39
mcs.c
@ -176,7 +176,16 @@ BOOL mcs_recv(HCONN conn, BOOL request)
|
||||
{
|
||||
MCS_DATA data;
|
||||
|
||||
return (iso_recv(conn)) && mcs_io_data(&conn->in, &data, request);
|
||||
if (!iso_recv(conn) || !mcs_io_data(&conn->in, &data, request))
|
||||
return False;
|
||||
|
||||
#ifdef MCS_DEBUG
|
||||
fprintf(stderr, "MCS packet\n");
|
||||
dump_data(conn->in.data+conn->in.offset, conn->in.end-conn->in.offset);
|
||||
#endif
|
||||
|
||||
conn->in.rdp_offset = conn->in.offset;
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Initialise a DOMAIN_PARAMS structure */
|
||||
@ -243,17 +252,21 @@ BOOL ber_io_header(STREAM s, BOOL islong, int tagval, int *length)
|
||||
BOOL res;
|
||||
|
||||
/* Read/write tag */
|
||||
if (islong) {
|
||||
if (islong)
|
||||
{
|
||||
word_tag = tagval;
|
||||
res = msb_io_uint16(s, &word_tag);
|
||||
tag = word_tag;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
byte_tag = tagval;
|
||||
res = prs_io_uint8(s, &byte_tag);
|
||||
tag = byte_tag;
|
||||
}
|
||||
|
||||
if (!res || (tag != tagval)) {
|
||||
if (!res || (tag != tagval))
|
||||
{
|
||||
fprintf(stderr, "Invalid ASN.1 tag\n");
|
||||
return False;
|
||||
}
|
||||
@ -524,6 +537,7 @@ BOOL mcs_io_data(STREAM s, MCS_DATA *dt, BOOL request)
|
||||
{
|
||||
uint8 opcode = (request ? 25 : 26) << 2;
|
||||
uint8 pkt_opcode = opcode;
|
||||
uint8 byte1, byte2;
|
||||
BOOL res;
|
||||
|
||||
res = prs_io_uint8(s, &pkt_opcode);
|
||||
@ -538,7 +552,22 @@ BOOL mcs_io_data(STREAM s, MCS_DATA *dt, BOOL request)
|
||||
res = res ? msb_io_uint16(s, &dt->userid) : False;
|
||||
res = res ? msb_io_uint16(s, &dt->chanid) : False;
|
||||
res = res ? prs_io_uint8 (s, &dt->flags ) : False;
|
||||
res = res ? msb_io_uint16(s, &dt->length) : False;
|
||||
|
||||
if (s->marshall)
|
||||
{
|
||||
res = res ? msb_io_uint16(s, &dt->length) : False;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = res ? prs_io_uint8(s, &byte1) : False;
|
||||
if (byte1 & 0x80)
|
||||
{
|
||||
res = res ? prs_io_uint8(s, &byte2) : False;
|
||||
dt->length = ((byte1 & ~0x80) << 8) + byte2;
|
||||
}
|
||||
else dt->length = byte1;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
1
parse.h
1
parse.h
@ -41,6 +41,7 @@ typedef struct connection
|
||||
{
|
||||
/* User interface */
|
||||
HWINDOW wnd;
|
||||
HBITMAP bmpcache[8];
|
||||
|
||||
/* Parsing layer */
|
||||
struct stream in;
|
||||
|
21
proto.h
21
proto.h
@ -75,7 +75,12 @@ BOOL mcs_io_data(STREAM s, MCS_DATA *dt, BOOL request);
|
||||
/* RDP layer */
|
||||
HCONN rdp_connect(char *server);
|
||||
void rdp_main_loop(HCONN conn);
|
||||
void process_opaque_rect(HCONN conn, RDP_ORDER_STATE *os, BOOL delta);
|
||||
void process_bmpcache(HCONN conn);
|
||||
void process_orders(HCONN conn, RDP_ORDER_STATE *os);
|
||||
void process_palette(HCONN conn);
|
||||
void process_update(HCONN conn, RDP_ORDER_STATE *os);
|
||||
void process_pointer(HCONN conn);
|
||||
void rdp_establish_key(HCONN conn);
|
||||
void rdp_send_cert(HCONN conn);
|
||||
void rdp_send_confirm_active(HCONN conn);
|
||||
@ -105,6 +110,8 @@ void rdp_make_font_pdu(RDP_FONT_PDU *pdu, uint16 seqno);
|
||||
void rdp_make_input_pdu(RDP_INPUT_PDU *pdu);
|
||||
BOOL rdp_io_header(STREAM s, RDP_HEADER *hdr);
|
||||
BOOL rdp_io_data_header(STREAM s, RDP_DATA_HEADER *hdr);
|
||||
BOOL rdp_io_coord(STREAM s, uint16 *coord, BOOL delta);
|
||||
BOOL rdp_io_colormap(STREAM s, COLORMAP *colors);
|
||||
BOOL rdp_io_general_caps(STREAM s, RDP_GENERAL_CAPS *caps);
|
||||
BOOL rdp_io_bitmap_caps(STREAM s, RDP_BITMAP_CAPS *caps);
|
||||
BOOL rdp_io_order_caps(STREAM s, RDP_ORDER_CAPS *caps);
|
||||
@ -125,17 +132,25 @@ BOOL rdp_io_font_pdu(STREAM s, RDP_FONT_PDU *pdu);
|
||||
BOOL rdp_io_update_pdu(STREAM s, RDP_UPDATE_PDU *pdu);
|
||||
BOOL rdp_io_secondary_order(STREAM s, RDP_SECONDARY_ORDER *rso);
|
||||
BOOL rdp_io_bitmap_header(STREAM s, RDP_BITMAP_HEADER *rdh);
|
||||
BOOL rdp_io_pointer(STREAM s, RDP_POINTER *ptr);
|
||||
|
||||
|
||||
/* Utility routines */
|
||||
void *xmalloc(int size);
|
||||
void *xrealloc(void *oldmem, int size);
|
||||
BOOL bitmap_decompress(unsigned char *input, int size,
|
||||
unsigned char *output, int width);
|
||||
void dump_data(unsigned char *p, int len);
|
||||
BOOL bitmap_decompress(unsigned char *output, int width, int height,
|
||||
unsigned char *input, int size);
|
||||
|
||||
/* User interface routines */
|
||||
HWINDOW ui_create_window(int width, int height);
|
||||
void ui_destroy_window(HWINDOW wnd);
|
||||
HBITMAP ui_create_bitmap(HWINDOW wnd, int width, int height, uint8 *data);
|
||||
void ui_destroy_bitmap(HBITMAP bmp);
|
||||
void ui_destroy_bitmap(HWINDOW wnd, HBITMAP bmp);
|
||||
void ui_paint_bitmap(HWINDOW wnd, HBITMAP bmp, int x, int y);
|
||||
HCOLORMAP ui_create_colormap(HWINDOW wnd, COLORMAP *colors);
|
||||
void ui_destroy_colormap(HWINDOW wnd, HCOLORMAP map);
|
||||
void ui_set_colormap(HWINDOW wnd, HCOLORMAP map);
|
||||
void ui_draw_rectangle(HWINDOW wnd, int x, int y, int width, int height);
|
||||
void ui_move_pointer(HWINDOW wnd, int x, int y);
|
||||
|
||||
|
269
rdp.c
269
rdp.c
@ -34,6 +34,7 @@ HCONN rdp_connect(char *server)
|
||||
mcs_recv(conn, False); /* Server's licensing certificate */
|
||||
rdp_send_cert(conn);
|
||||
mcs_recv(conn, False);
|
||||
mcs_recv(conn, False); /* Demand active */
|
||||
|
||||
if (!rdp_recv_pdu(conn, &type) || (type != RDP_PDU_DEMAND_ACTIVE))
|
||||
{
|
||||
@ -61,7 +62,6 @@ HCONN rdp_connect(char *server)
|
||||
void rdp_main_loop(HCONN conn)
|
||||
{
|
||||
RDP_DATA_HEADER hdr;
|
||||
RDP_UPDATE_PDU update;
|
||||
RDP_ORDER_STATE os;
|
||||
uint8 type;
|
||||
|
||||
@ -70,37 +70,75 @@ void rdp_main_loop(HCONN conn)
|
||||
while (rdp_recv_pdu(conn, &type))
|
||||
{
|
||||
if (type != RDP_PDU_DATA)
|
||||
{
|
||||
fprintf(stderr, "Unknown PDU 0x%x\n", type);
|
||||
continue;
|
||||
}
|
||||
|
||||
rdp_io_data_header(&conn->in, &hdr);
|
||||
|
||||
switch (hdr.data_pdu_type)
|
||||
{
|
||||
case RDP_DATA_PDU_UPDATE:
|
||||
rdp_io_update_pdu(&conn->in, &update);
|
||||
if (update.update_type == RDP_UPDATE_ORDERS)
|
||||
{
|
||||
fprintf(stderr, "Received orders\n");
|
||||
process_orders(conn, &os);
|
||||
}
|
||||
break;
|
||||
case RDP_DATA_PDU_UPDATE:
|
||||
process_update(conn, &os);
|
||||
break;
|
||||
|
||||
case RDP_DATA_PDU_POINTER:
|
||||
process_pointer(conn);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "Unknown data PDU 0x%x\n",
|
||||
hdr.data_pdu_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void prs_io_coord(STREAM s, uint16 *coord, BOOL delta)
|
||||
void process_memblt(HCONN conn, RDP_ORDER_STATE *os, BOOL delta)
|
||||
{
|
||||
uint8 change;
|
||||
HBITMAP hbitmap;
|
||||
uint16 present;
|
||||
lsb_io_uint16(&conn->in, &present);
|
||||
|
||||
if (delta)
|
||||
if (present & 1)
|
||||
prs_io_uint8(&conn->in, &os->memblt.cache_id);
|
||||
|
||||
if (present & 2)
|
||||
rdp_io_coord(&conn->in, &os->memblt.x, delta);
|
||||
|
||||
if (present & 4)
|
||||
rdp_io_coord(&conn->in, &os->memblt.y, delta);
|
||||
|
||||
if (present & 8)
|
||||
rdp_io_coord(&conn->in, &os->memblt.cx, delta);
|
||||
|
||||
if (present & 16)
|
||||
rdp_io_coord(&conn->in, &os->memblt.cy, delta);
|
||||
|
||||
if (present & 32)
|
||||
prs_io_uint8(&conn->in, &os->memblt.opcode);
|
||||
|
||||
if (present & 256)
|
||||
lsb_io_uint16(&conn->in, &os->memblt.cache_idx);
|
||||
|
||||
if (os->memblt.opcode != 0xcc) /* SRCCOPY */
|
||||
{
|
||||
prs_io_uint8(s, &change);
|
||||
*coord += change;
|
||||
fprintf(stderr, "Unsupported raster operation 0x%x\n",
|
||||
os->memblt.opcode);
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
if ((os->memblt.cache_idx > NUM_ELEMENTS(conn->bmpcache))
|
||||
|| ((hbitmap = conn->bmpcache[os->memblt.cache_idx]) == NULL))
|
||||
{
|
||||
lsb_io_uint16(s, coord);
|
||||
fprintf(stderr, "Bitmap %d not found\n", os->memblt.cache_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(stderr, "MEMBLT %d:%dx%d\n", os->memblt.cache_idx,
|
||||
os->memblt.x, os->memblt.y);
|
||||
|
||||
ui_paint_bitmap(conn->wnd, hbitmap, os->memblt.x, os->memblt.y);
|
||||
}
|
||||
|
||||
void process_opaque_rect(HCONN conn, RDP_ORDER_STATE *os, BOOL delta)
|
||||
@ -109,45 +147,60 @@ void process_opaque_rect(HCONN conn, RDP_ORDER_STATE *os, BOOL delta)
|
||||
prs_io_uint8(&conn->in, &present);
|
||||
|
||||
if (present & 1)
|
||||
prs_io_coord(&conn->in, &os->opaque_rect.x, delta);
|
||||
rdp_io_coord(&conn->in, &os->opaque_rect.x, delta);
|
||||
|
||||
if (present & 2)
|
||||
prs_io_coord(&conn->in, &os->opaque_rect.y, delta);
|
||||
rdp_io_coord(&conn->in, &os->opaque_rect.y, delta);
|
||||
|
||||
if (present & 4)
|
||||
prs_io_coord(&conn->in, &os->opaque_rect.cx, delta);
|
||||
rdp_io_coord(&conn->in, &os->opaque_rect.cx, delta);
|
||||
|
||||
if (present & 8)
|
||||
prs_io_coord(&conn->in, &os->opaque_rect.cy, delta);
|
||||
rdp_io_coord(&conn->in, &os->opaque_rect.cy, delta);
|
||||
|
||||
if (present & 16)
|
||||
prs_io_uint8(&conn->in, &os->opaque_rect.colour);
|
||||
|
||||
fprintf(stderr, "Opaque rectangle at %d, %d\n", os->opaque_rect.x, os->opaque_rect.y);
|
||||
ui_draw_rectangle(conn->wnd, os->opaque_rect.x, os->opaque_rect.y,
|
||||
os->opaque_rect.cx, os->opaque_rect.cy);
|
||||
}
|
||||
|
||||
void process_bmpcache(HCONN conn)
|
||||
{
|
||||
|
||||
RDP_BITMAP_HEADER rbh;
|
||||
char *bmpdata;
|
||||
HBITMAP bmp;
|
||||
static int x = 0;
|
||||
HBITMAP *entry;
|
||||
char *input, *bmpdata;
|
||||
|
||||
rdp_io_bitmap_header(&conn->in, &rbh);
|
||||
fprintf(stderr, "Decompressing bitmap %d x %d, final size %d\n", rbh.width, rbh.height, rbh.final_size);
|
||||
fprintf(stderr, "BMPCACHE %d:%dx%d\n", rbh.cache_idx,
|
||||
rbh.width, rbh.height);
|
||||
|
||||
input = conn->in.data + conn->in.offset;
|
||||
conn->in.offset += rbh.size;
|
||||
// dump_data(conn->in.data+conn->in.offset, conn->in.rdp_offset-conn->in.offset);
|
||||
|
||||
bmpdata = malloc(rbh.width * rbh.height);
|
||||
bitmap_decompress(conn->in.data
|
||||
+ conn->in.offset, rbh.size,
|
||||
bmpdata, rbh.width);
|
||||
conn->in.offset += rbh.size;
|
||||
if (!bitmap_decompress(bmpdata, rbh.width, rbh.height, input, rbh.size))
|
||||
{
|
||||
fprintf(stderr, "Decompression failed\n");
|
||||
free(bmpdata);
|
||||
return;
|
||||
}
|
||||
|
||||
bmp = ui_create_bitmap(conn->wnd, rbh.width, rbh.height, bmpdata);
|
||||
ui_paint_bitmap(conn->wnd, bmp, x, 0);
|
||||
ui_destroy_bitmap(bmp);
|
||||
if (rbh.cache_idx > NUM_ELEMENTS(conn->bmpcache))
|
||||
{
|
||||
fprintf(stderr, "Attempted store past end of cache");
|
||||
return;
|
||||
}
|
||||
|
||||
x += rbh.width;
|
||||
entry = &conn->bmpcache[rbh.cache_idx];
|
||||
// if (*entry != NULL)
|
||||
// ui_destroy_bitmap(conn->wnd, *entry);
|
||||
|
||||
*entry = ui_create_bitmap(conn->wnd, rbh.width, rbh.height, bmpdata);
|
||||
// ui_paint_bitmap(conn->wnd, bmp, x, 0);
|
||||
// ui_destroy_bitmap(conn->wnd, bmp);
|
||||
}
|
||||
|
||||
void process_orders(HCONN conn, RDP_ORDER_STATE *os)
|
||||
@ -155,6 +208,7 @@ void process_orders(HCONN conn, RDP_ORDER_STATE *os)
|
||||
uint16 num_orders;
|
||||
int processed = 0;
|
||||
BOOL res = True;
|
||||
BOOL delta;
|
||||
// unsigned char *p;
|
||||
|
||||
lsb_io_uint16(&conn->in, &num_orders);
|
||||
@ -169,6 +223,10 @@ void process_orders(HCONN conn, RDP_ORDER_STATE *os)
|
||||
uint8 order_flags;
|
||||
|
||||
prs_io_uint8(&conn->in, &order_flags);
|
||||
fprintf(stderr, "Order flags: 0x%x\n", order_flags);
|
||||
|
||||
if (order_flags == 0x51) /* ?? */
|
||||
return;
|
||||
|
||||
if (!(order_flags & RDP_ORDER_STANDARD))
|
||||
return;
|
||||
@ -188,27 +246,84 @@ void process_orders(HCONN conn, RDP_ORDER_STATE *os)
|
||||
rso.type);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (order_flags & RDP_ORDER_CHANGE)
|
||||
prs_io_uint8(&conn->in, &os->order_type);
|
||||
|
||||
switch (os->order_type)
|
||||
else
|
||||
{
|
||||
case RDP_ORDER_OPAQUE_RECT:
|
||||
process_opaque_rect(conn, os, order_flags & RDP_ORDER_DELTA);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown order %d\n", os->order_type);
|
||||
return;
|
||||
if (order_flags & RDP_ORDER_CHANGE)
|
||||
prs_io_uint8(&conn->in, &os->order_type);
|
||||
|
||||
delta = order_flags & RDP_ORDER_DELTA;
|
||||
|
||||
switch (os->order_type)
|
||||
{
|
||||
case RDP_ORDER_OPAQUE_RECT:
|
||||
process_opaque_rect(conn, os, delta);
|
||||
break;
|
||||
|
||||
case RDP_ORDER_MEMBLT:
|
||||
process_memblt(conn, os, delta);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "Unknown order %d\n", os->order_type);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
processed++;
|
||||
}
|
||||
}
|
||||
|
||||
void process_palette(HCONN conn)
|
||||
{
|
||||
HCOLORMAP map;
|
||||
COLORMAP colors;
|
||||
|
||||
rdp_io_colormap(&conn->in, &colors);
|
||||
map = ui_create_colormap(conn->wnd, &colors);
|
||||
ui_set_colormap(conn->wnd, map);
|
||||
// ui_destroy_colormap(map);
|
||||
}
|
||||
|
||||
void process_update(HCONN conn, RDP_ORDER_STATE *os)
|
||||
{
|
||||
RDP_UPDATE_PDU update;
|
||||
|
||||
rdp_io_update_pdu(&conn->in, &update);
|
||||
switch (update.update_type)
|
||||
{
|
||||
case RDP_UPDATE_ORDERS:
|
||||
process_orders(conn, os);
|
||||
break;
|
||||
case RDP_UPDATE_PALETTE:
|
||||
process_palette(conn);
|
||||
break;
|
||||
case RDP_UPDATE_SYNCHRONIZE:
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown update 0x%x\n",
|
||||
update.update_type);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void process_pointer(HCONN conn)
|
||||
{
|
||||
RDP_POINTER ptr;
|
||||
|
||||
rdp_io_pointer(&conn->in, &ptr);
|
||||
|
||||
switch (ptr.message)
|
||||
{
|
||||
case RDP_POINTER_MOVE:
|
||||
ui_move_pointer(conn->wnd, ptr.x, ptr.y);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown pointer message 0x%x\n",
|
||||
ptr.message);
|
||||
}
|
||||
}
|
||||
|
||||
/* Work this out later. This is useless anyway when encryption is off. */
|
||||
uint8 precanned_key_packet[] = {
|
||||
0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x00,0x00,
|
||||
@ -420,10 +535,25 @@ BOOL rdp_recv_pdu(HCONN conn, uint8 *type)
|
||||
{
|
||||
RDP_HEADER hdr;
|
||||
|
||||
if (!mcs_recv(conn, False) || !rdp_io_header(&conn->in, &hdr))
|
||||
conn->in.offset = conn->in.rdp_offset;
|
||||
|
||||
if (conn->in.offset >= conn->in.end)
|
||||
{
|
||||
if (!mcs_recv(conn, False))
|
||||
return False;
|
||||
}
|
||||
|
||||
if (!rdp_io_header(&conn->in, &hdr))
|
||||
return False;
|
||||
|
||||
conn->in.rdp_offset += hdr.length;
|
||||
*type = hdr.pdu_type & 0xf;
|
||||
|
||||
#if DEBUG
|
||||
fprintf(stderr, "RDP packet (type %x):\n", *type);
|
||||
dump_data(conn->in.data+conn->in.offset, conn->in.rdp_offset-conn->in.offset);
|
||||
#endif
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
@ -625,6 +755,39 @@ BOOL rdp_io_data_header(STREAM s, RDP_DATA_HEADER *hdr)
|
||||
return res;
|
||||
}
|
||||
|
||||
BOOL rdp_io_coord(STREAM s, uint16 *coord, BOOL delta)
|
||||
{
|
||||
uint8 change;
|
||||
BOOL res;
|
||||
|
||||
if (delta)
|
||||
{
|
||||
res = prs_io_uint8(s, &change);
|
||||
*coord += change;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = lsb_io_uint16(s, coord);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
BOOL rdp_io_colormap(STREAM s, COLORMAP *colors)
|
||||
{
|
||||
int datasize;
|
||||
|
||||
lsb_io_uint16(s, &colors->ncolors);
|
||||
datasize = colors->ncolors * 3;
|
||||
|
||||
if (datasize > sizeof(colors->colors))
|
||||
return False;
|
||||
|
||||
memcpy(colors->colors, s->data + s->offset, datasize);
|
||||
s->offset += datasize;
|
||||
return True;
|
||||
}
|
||||
|
||||
BOOL rdp_io_general_caps(STREAM s, RDP_GENERAL_CAPS *caps)
|
||||
{
|
||||
uint16 length = RDP_CAPLEN_GENERAL;
|
||||
@ -1153,3 +1316,15 @@ BOOL rdp_io_bitmap_header(STREAM s, RDP_BITMAP_HEADER *rdh)
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
BOOL rdp_io_pointer(STREAM s, RDP_POINTER *ptr)
|
||||
{
|
||||
BOOL res = True;
|
||||
|
||||
res = res ? lsb_io_uint16(s, &ptr->message) : False;
|
||||
res = res ? lsb_io_uint16(s, &ptr->pad ) : False;
|
||||
res = res ? lsb_io_uint16(s, &ptr->x ) : False;
|
||||
res = res ? lsb_io_uint16(s, &ptr->y ) : False;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
33
rdp.h
33
rdp.h
@ -305,8 +305,9 @@ typedef struct _RDP_FONT_PDU
|
||||
|
||||
} RDP_FONT_PDU;
|
||||
|
||||
#define RDP_UPDATE_ORDERS 0
|
||||
#define RDP_UPDATE_PALETTE 2
|
||||
#define RDP_UPDATE_ORDERS 0
|
||||
#define RDP_UPDATE_PALETTE 2
|
||||
#define RDP_UPDATE_SYNCHRONIZE 3
|
||||
|
||||
typedef struct _OPAQUE_RECT_ORDER
|
||||
{
|
||||
@ -318,11 +319,24 @@ typedef struct _OPAQUE_RECT_ORDER
|
||||
|
||||
} OPAQUE_RECT_ORDER;
|
||||
|
||||
typedef struct _MEMBLT_ORDER
|
||||
{
|
||||
uint8 cache_id;
|
||||
uint16 x;
|
||||
uint16 y;
|
||||
uint16 cx;
|
||||
uint16 cy;
|
||||
uint8 opcode;
|
||||
uint16 cache_idx;
|
||||
|
||||
} MEMBLT_ORDER;
|
||||
|
||||
typedef struct _RDP_ORDER_STATE
|
||||
{
|
||||
uint8 order_type;
|
||||
|
||||
OPAQUE_RECT_ORDER opaque_rect;
|
||||
MEMBLT_ORDER memblt;
|
||||
|
||||
} RDP_ORDER_STATE;
|
||||
|
||||
@ -342,7 +356,8 @@ typedef struct _RDP_UPDATE_PDU
|
||||
|
||||
enum RDP_ORDER_TYPE
|
||||
{
|
||||
RDP_ORDER_OPAQUE_RECT = 10
|
||||
RDP_ORDER_OPAQUE_RECT = 10,
|
||||
RDP_ORDER_MEMBLT = 13
|
||||
};
|
||||
|
||||
enum RDP_SECONDARY_ORDER_TYPE
|
||||
@ -373,3 +388,15 @@ typedef struct _RDP_BITMAP_HEADER
|
||||
uint16 final_size;
|
||||
|
||||
} RDP_BITMAP_HEADER;
|
||||
|
||||
#define RDP_POINTER_MOVE 3
|
||||
|
||||
typedef struct _RDP_POINTER
|
||||
{
|
||||
uint16 message;
|
||||
uint16 pad;
|
||||
uint16 x;
|
||||
uint16 y;
|
||||
|
||||
} RDP_POINTER;
|
||||
|
||||
|
60
xwin.c
60
xwin.c
@ -45,6 +45,8 @@ HWINDOW ui_create_window(int width, int height)
|
||||
wnd->display = display;
|
||||
wnd->wnd = window;
|
||||
wnd->gc = gc;
|
||||
wnd->visual = DefaultVisual(wnd->display, DefaultScreen(wnd->display));
|
||||
|
||||
return wnd;
|
||||
}
|
||||
|
||||
@ -58,16 +60,14 @@ void ui_destroy_window(HWINDOW wnd)
|
||||
HBITMAP ui_create_bitmap(HWINDOW wnd, int width, int height, uint8 *data)
|
||||
{
|
||||
XImage *image;
|
||||
Visual *visual;
|
||||
|
||||
visual = DefaultVisual(wnd->display, DefaultScreen(wnd->display));
|
||||
image = XCreateImage(wnd->display, visual, 8, ZPixmap, 0,
|
||||
image = XCreateImage(wnd->display, wnd->visual, 8, ZPixmap, 0,
|
||||
data, width, height, 32, width);
|
||||
|
||||
return (HBITMAP)image;
|
||||
}
|
||||
|
||||
void ui_destroy_bitmap(HBITMAP bmp)
|
||||
void ui_destroy_bitmap(HWINDOW wnd, HBITMAP bmp)
|
||||
{
|
||||
XDestroyImage((XImage *)bmp);
|
||||
}
|
||||
@ -81,3 +81,55 @@ void ui_paint_bitmap(HWINDOW wnd, HBITMAP bmp, int x, int y)
|
||||
|
||||
XSync(wnd->display, True);
|
||||
}
|
||||
|
||||
HCOLORMAP ui_create_colormap(HWINDOW wnd, COLORMAP *colors)
|
||||
{
|
||||
COLORENTRY *entry;
|
||||
XColor *xcolors, *xentry;
|
||||
Colormap map;
|
||||
int i, ncolors = colors->ncolors;
|
||||
|
||||
xcolors = malloc(sizeof(XColor) * ncolors);
|
||||
for (i = 0; i < ncolors; i++)
|
||||
{
|
||||
entry = &colors->colors[i];
|
||||
xentry = &xcolors[i];
|
||||
|
||||
xentry->pixel = i;
|
||||
xentry->red = entry->red << 8;
|
||||
xentry->blue = entry->blue << 8;
|
||||
xentry->green = entry->green << 8;
|
||||
xentry->flags = DoRed | DoBlue | DoGreen;
|
||||
}
|
||||
|
||||
map = XCreateColormap(wnd->display, wnd->wnd, wnd->visual, AllocAll);
|
||||
XStoreColors(wnd->display, map, xcolors, ncolors);
|
||||
|
||||
free(xcolors);
|
||||
return (HCOLORMAP)map;
|
||||
}
|
||||
|
||||
void ui_destroy_colormap(HWINDOW wnd, HCOLORMAP map)
|
||||
{
|
||||
XFreeColormap(wnd->display, (Colormap)map);
|
||||
}
|
||||
|
||||
void ui_set_colormap(HWINDOW wnd, HCOLORMAP map)
|
||||
{
|
||||
XSetWindowColormap(wnd->display, wnd->wnd, (Colormap)map);
|
||||
}
|
||||
|
||||
void ui_draw_rectangle(HWINDOW wnd, int x, int y, int width, int height)
|
||||
{
|
||||
static int white = 0;
|
||||
|
||||
XSetForeground(wnd->display, wnd->gc, white);
|
||||
XFillRectangle(wnd->display, wnd->wnd, wnd->gc, x, y, width, height);
|
||||
|
||||
white++;
|
||||
}
|
||||
|
||||
void ui_move_pointer(HWINDOW wnd, int x, int y)
|
||||
{
|
||||
XWarpPointer(wnd->display, wnd->wnd, wnd->wnd, 0, 0, 0, 0, x, y);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user