diff --git a/libxrdp/libxrdp.c b/libxrdp/libxrdp.c index c3763bf5..b03db073 100644 --- a/libxrdp/libxrdp.c +++ b/libxrdp/libxrdp.c @@ -27,6 +27,8 @@ #define LLOGLN(_level, _args) \ do { if (_level < LOG_LEVEL) { g_writeln _args ; } } while (0) +#define MAX_BITMAP_BUF_SIZE (16 * 1024) /* 16K */ + /******************************************************************************/ struct xrdp_session *EXPORT_CC libxrdp_init(tbus id, struct trans *trans) @@ -373,15 +375,15 @@ libxrdp_send_bell(struct xrdp_session *session) return 0; } - /*****************************************************************************/ int EXPORT_CC libxrdp_send_bitmap(struct xrdp_session *session, int width, int height, int bpp, char *data, int x, int y, int cx, int cy) { - int line_size = 0; + int line_bytes = 0; int i = 0; int j = 0; + int k; int total_lines = 0; int lines_sending = 0; int Bpp = 0; @@ -389,27 +391,43 @@ libxrdp_send_bitmap(struct xrdp_session *session, int width, int height, int bufsize = 0; int total_bufsize = 0; int num_updates = 0; + int line_pad_bytes; + int server_line_bytes; char *p_num_updates = (char *)NULL; char *p = (char *)NULL; char *q = (char *)NULL; struct stream *s = (struct stream *)NULL; struct stream *temp_s = (struct stream *)NULL; + tui32 pixel; - DEBUG(("libxrdp_send_bitmap sending bitmap")); + LLOGLN(10, ("libxrdp_send_bitmap: sending bitmap")); Bpp = (bpp + 7) / 8; - e = width % 4; - - if (e != 0) + e = (4 - width) & 3; + switch (bpp) { - e = 4 - e; + case 15: + case 16: + server_line_bytes = width * 2; + break; + case 24: + case 32: + server_line_bytes = width * 4; + break; + default: /* 8 bpp */ + server_line_bytes = width; + break; } + line_bytes = width * Bpp; + line_pad_bytes = line_bytes + e * Bpp; - line_size = width * Bpp; + LLOGLN(10, ("libxrdp_send_bitmap: bpp %d Bpp %d line_bytes %d " + "server_line_bytes %d", bpp, Bpp, line_bytes, server_line_bytes)); make_stream(s); - init_stream(s, 8192); + init_stream(s, MAX_BITMAP_BUF_SIZE); if (session->client_info->use_bitmap_comp) { + LLOGLN(10, ("libxrdp_send_bitmap: compression")); make_stream(temp_s); init_stream(temp_s, 65536); i = 0; @@ -421,6 +439,8 @@ libxrdp_send_bitmap(struct xrdp_session *session, int width, int height, while (i > 0) { + LLOGLN(10, ("libxrdp_send_bitmap: i %d", i)); + total_bufsize = 0; num_updates = 0; xrdp_rdp_init_data((struct xrdp_rdp *)session->rdp, s); @@ -440,10 +460,26 @@ libxrdp_send_bitmap(struct xrdp_session *session, int width, int height, } p = s->p; - lines_sending = xrdp_bitmap_compress(data, width, height, - s, bpp, - 4096 - total_bufsize, - i - 1, temp_s, e); + + if (bpp > 24) + { + LLOGLN(10, ("libxrdp_send_bitmap: 32 bpp")); + lines_sending = xrdp_bitmap32_compress(data, width, height, + s, 32, + (MAX_BITMAP_BUF_SIZE - 100) - total_bufsize, + i - 1, temp_s, e, 0x10); + LLOGLN(10, ("libxrdp_send_bitmap: i %d lines_sending %d", + i, lines_sending)); + } + else + { + lines_sending = xrdp_bitmap_compress(data, width, height, + s, bpp, + (MAX_BITMAP_BUF_SIZE - 100) - total_bufsize, + i - 1, temp_s, e); + LLOGLN(10, ("libxrdp_send_bitmap: i %d lines_sending %d", + i, lines_sending)); + } if (lines_sending == 0) { @@ -470,6 +506,7 @@ libxrdp_send_bitmap(struct xrdp_session *session, int width, int height, out_uint16_le(s, bufsize); /* compressed size */ j = (width + e) * Bpp; j = j * lines_sending; + total_bufsize += 18; } else { @@ -481,31 +518,42 @@ libxrdp_send_bitmap(struct xrdp_session *session, int width, int height, out_uint16_le(s, j); /* line size */ j = j * lines_sending; out_uint16_le(s, j); /* final size */ + total_bufsize += 26; } - if (j > 32768) + LLOGLN(10, ("libxrdp_send_bitmap: decompressed pixels %d " + "decompressed bytes %d compressed bytes %d", + lines_sending * (width + e), + line_pad_bytes * lines_sending, bufsize)); + + if (j > MAX_BITMAP_BUF_SIZE) { - g_writeln("error, decompressed size too big: %d bytes", j); + LLOGLN(0, ("libxrdp_send_bitmap: error, decompressed " + "size too big: %d bytes", j)); } - if (bufsize > 8192) + if (bufsize > MAX_BITMAP_BUF_SIZE) { - g_writeln("error, compressed size too big: %d bytes", bufsize); + LLOGLN(0, ("libxrdp_send_bitmap: error, compressed size " + "too big: %d bytes", bufsize)); } s->p = s->end; } - while (total_bufsize < 4096 && i > 0); + while (total_bufsize < MAX_BITMAP_BUF_SIZE && i > 0); + + LLOGLN(10, ("libxrdp_send_bitmap: num_updates %d total_bufsize %d", + num_updates, total_bufsize)); p_num_updates[0] = num_updates; p_num_updates[1] = num_updates >> 8; xrdp_rdp_send_data((struct xrdp_rdp *)session->rdp, s, RDP_DATA_PDU_UPDATE); - if (total_bufsize > 8192) + if (total_bufsize > MAX_BITMAP_BUF_SIZE) { - g_writeln("error, total compressed size too big: %d bytes", - total_bufsize); + LLOGLN(0, ("libxrdp_send_bitmap: error, total compressed " + "size too big: %d bytes", total_bufsize)); } } @@ -513,22 +561,30 @@ libxrdp_send_bitmap(struct xrdp_session *session, int width, int height, } else { + LLOGLN(10, ("libxrdp_send_bitmap: no compression")); total_lines = height; i = 0; p = data; - if (line_size > 0 && total_lines > 0) + if (line_bytes > 0 && total_lines > 0) { while (i < total_lines) { - lines_sending = 4096 / (line_size + e * Bpp); + + lines_sending = (MAX_BITMAP_BUF_SIZE - 100) / (line_pad_bytes); if (i + lines_sending > total_lines) { lines_sending = total_lines - i; } - p = p + line_size * lines_sending; + if (lines_sending == 0) + { + LLOGLN(0, ("libxrdp_send_bitmap: error, lines_sending == zero")); + break; + } + + p = p + server_line_bytes * lines_sending; xrdp_rdp_init_data((struct xrdp_rdp *)session->rdp, s); out_uint16_le(s, RDP_UPDATE_BITMAP); out_uint16_le(s, 1); /* num updates */ @@ -540,14 +596,67 @@ libxrdp_send_bitmap(struct xrdp_session *session, int width, int height, out_uint16_le(s, lines_sending); out_uint16_le(s, bpp); /* bpp */ out_uint16_le(s, 0); /* compress */ - out_uint16_le(s, (line_size + e * Bpp) * lines_sending); /* bufsize */ + out_uint16_le(s, line_pad_bytes * lines_sending); /* bufsize */ q = p; - for (j = 0; j < lines_sending; j++) + switch (bpp) { - q = q - line_size; - out_uint8a(s, q, line_size); /* B_ENDIAN doesn't work here, todo */ - out_uint8s(s, e * Bpp); + case 15: + case 16: + for (j = 0; j < lines_sending; j++) + { + q = q - server_line_bytes; + for (k = 0; k < width; k++) + { + pixel = *((tui16*)(q + k * 2)); + out_uint16_le(s, pixel); + } + for (k = 0; k < e; k++) + { + out_uint8s(s, 2); + } + } + break; + case 24: + for (j = 0; j < lines_sending; j++) + { + q = q - server_line_bytes; + for (k = 0; k < width; k++) + { + pixel = *((tui32*)(q + k * 4)); + out_uint8(s, pixel); + out_uint8(s, pixel >> 8); + out_uint8(s, pixel >> 16); + } + for (k = 0; k < e; k++) + { + out_uint8s(s, 3); + } + } + break; + case 32: + for (j = 0; j < lines_sending; j++) + { + q = q - server_line_bytes; + for (k = 0; k < width; k++) + { + pixel = *((int*)(q + k * 4)); + out_uint32_le(s, pixel); + } + for (k = 0; k < e; k++) + { + out_uint8s(s, 4); + } + } + break; + default: /* 8 bpp */ + for (j = 0; j < lines_sending; j++) + { + q = q - line_bytes; + out_uint8a(s, q, line_bytes); + out_uint8s(s, e * Bpp); + } + break; } s_mark_end(s); diff --git a/libxrdp/xrdp_caps.c b/libxrdp/xrdp_caps.c index 8d5250d5..35778b5b 100644 --- a/libxrdp/xrdp_caps.c +++ b/libxrdp/xrdp_caps.c @@ -80,6 +80,7 @@ xrdp_caps_process_general(struct xrdp_rdp *self, struct stream *s, in_uint8s(s, 6); in_uint16_le(s, extraFlags); /* extraFlags (2 bytes) */ + self->client_info.op1 = extraFlags & NO_BITMAP_COMPRESSION_HDR; /* use_compact_packets is pretty much 'use rdp5' */ self->client_info.use_compact_packets = (extraFlags != 0); /* op2 is a boolean to use compact bitmap headers in bitmap cache */