/* This program 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 program 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 program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Copyright (C) Jay Sorg 2004 orders */ #include "xrdp.h" /*****************************************************************************/ struct xrdp_orders* xrdp_orders_create(struct xrdp_process* owner) { struct xrdp_orders* self; self = (struct xrdp_orders*)g_malloc(sizeof(struct xrdp_orders), 1); self->pro_layer = owner; self->rdp_layer = owner->rdp_layer; make_stream(self->out_s); init_stream(self->out_s, 8192); return self; } /*****************************************************************************/ void xrdp_orders_delete(struct xrdp_orders* self) { free_stream(self->out_s); g_free(self); } /*****************************************************************************/ /* returns error */ int xrdp_orders_init(struct xrdp_orders* self) { self->order_level++; if (self->order_level == 1) { self->order_count = 0; /* is this big enough */ if (xrdp_rdp_init_data(self->rdp_layer, self->out_s) != 0) return 1; out_uint16_le(self->out_s, RDP_UPDATE_ORDERS); out_uint8s(self->out_s, 2); /* pad */ self->order_count_ptr = self->out_s->p; out_uint8s(self->out_s, 2); /* number of orders, set later */ out_uint8s(self->out_s, 2); /* pad */ } return 0; } /*****************************************************************************/ /* returns error */ int xrdp_orders_send(struct xrdp_orders* self) { int rv; rv = 0; if (self->order_level > 0) { self->order_level--; if (self->order_level == 0) { s_mark_end(self->out_s); *((short*)self->order_count_ptr) = self->order_count; if (xrdp_rdp_send_data(self->rdp_layer, self->out_s, RDP_DATA_PDU_UPDATE) != 0) rv = 1; } } return rv; } /*****************************************************************************/ /* returns error */ int xrdp_orders_force_send(struct xrdp_orders* self) { if (self->order_count > 0) { s_mark_end(self->out_s); *((short*)self->order_count_ptr) = self->order_count; if (xrdp_rdp_send_data(self->rdp_layer, self->out_s, RDP_DATA_PDU_UPDATE) != 0) return 1; } self->order_count = 0; self->order_level = 0; return 0; } /*****************************************************************************/ int xrdp_orders_check(struct xrdp_orders* self, int max_size) { int size; if (self->order_level < 1) { if (max_size > 8000) return 1; else return 0; } size = self->out_s->p - self->order_count_ptr; if (size < 0 || size > 8192) return 1; if (size + max_size + 100 > 8000) { xrdp_orders_force_send(self); xrdp_orders_init(self); } return 0; } /*****************************************************************************/ /* returns boolean */ int xrdp_orders_last_bounds(struct xrdp_orders* self, struct xrdp_rect* rect) { if (rect == 0) return 0; if (rect->left == self->clip_left && rect->top == self->clip_top && rect->right == self->clip_right && rect->bottom == self->clip_bottom) return 1; return 0; } /*****************************************************************************/ /* returns boolean */ int xrdp_orders_send_delta(struct xrdp_orders* self, int* vals, int count) { int i; for (i = 0; i < count; i += 2) if (g_abs(vals[i] - vals[i + 1]) >= 128) return 0; return 1; } /*****************************************************************************/ /* returns error */ int xrdp_orders_out_bounds(struct xrdp_orders* self, struct xrdp_rect* rect) { char* bounds_flags_ptr; int bounds_flags; bounds_flags = 0; bounds_flags_ptr = self->out_s->p; out_uint8s(self->out_s, 1); /* left */ if (rect->left == self->clip_left) ; else if (g_abs(rect->left - self->clip_left) < 128) bounds_flags |= 0x10; else bounds_flags |= 0x01; /* top */ if (rect->top == self->clip_top) ; else if (g_abs(rect->top - self->clip_top) < 128) bounds_flags |= 0x20; else bounds_flags |= 0x02; /* right */ if (rect->right == self->clip_right) ; else if (g_abs(rect->right - self->clip_right) < 128) bounds_flags |= 0x40; else bounds_flags |= 0x04; /* bottom */ if (rect->bottom == self->clip_bottom) ; else if (g_abs(rect->bottom - self->clip_bottom) < 128) bounds_flags |= 0x80; else bounds_flags |= 0x08; /* left */ if (bounds_flags & 0x01) out_uint16_le(self->out_s, rect->left) else if (bounds_flags & 0x10) out_uint8(self->out_s, rect->left - self->clip_left) self->clip_left = rect->left; /* top */ if (bounds_flags & 0x02) out_uint16_le(self->out_s, rect->top) else if (bounds_flags & 0x20) out_uint8(self->out_s, rect->top - self->clip_top) self->clip_top = rect->top; /* right */ if (bounds_flags & 0x04) out_uint16_le(self->out_s, rect->right) else if (bounds_flags & 0x40) out_uint8(self->out_s, rect->right - self->clip_right) self->clip_right = rect->right; /* bottom */ if (bounds_flags & 0x08) out_uint16_le(self->out_s, rect->bottom) else if (bounds_flags & 0x80) out_uint8(self->out_s, rect->bottom - self->clip_bottom) self->clip_bottom = rect->bottom; /* set flags */ *bounds_flags_ptr = bounds_flags; return 0; } /*****************************************************************************/ /* returns error */ /* send a solid rect to client */ /* max size 23 */ int xrdp_orders_rect(struct xrdp_orders* self, int x, int y, int cx, int cy, int color, struct xrdp_rect* rect) { int order_flags; int vals[8]; int present; char* present_ptr; xrdp_orders_check(self, 23); self->order_count++; order_flags = RDP_ORDER_STANDARD; if (self->last_order != RDP_ORDER_RECT) order_flags |= RDP_ORDER_CHANGE; self->last_order = RDP_ORDER_RECT; if (rect != 0) { order_flags |= RDP_ORDER_BOUNDS; if (xrdp_orders_last_bounds(self, rect)) order_flags |= RDP_ORDER_LASTBOUNDS; } vals[0] = x; vals[1] = self->rect_x; vals[2] = y; vals[3] = self->rect_y; vals[4] = cx; vals[5] = self->rect_cx; vals[6] = cy; vals[7] = self->rect_cy; if (xrdp_orders_send_delta(self, vals, 8)) order_flags |= RDP_ORDER_DELTA; out_uint8(self->out_s, order_flags) if (order_flags & RDP_ORDER_CHANGE) out_uint8(self->out_s, self->last_order) present = 0; present_ptr = self->out_s->p; /* hold 1 byte present pointer */ out_uint8s(self->out_s, 1) if ((order_flags & RDP_ORDER_BOUNDS) && !(order_flags & RDP_ORDER_LASTBOUNDS)) xrdp_orders_out_bounds(self, rect); if (x != self->rect_x) { present |= 0x01; if (order_flags & RDP_ORDER_DELTA) out_uint8(self->out_s, x - self->rect_x) else out_uint16_le(self->out_s, x) self->rect_x = x; } if (y != self->rect_y) { present |= 0x02; if (order_flags & RDP_ORDER_DELTA) out_uint8(self->out_s, y - self->rect_y) else out_uint16_le(self->out_s, y) self->rect_y = y; } if (cx != self->rect_cx) { present |= 0x04; if (order_flags & RDP_ORDER_DELTA) out_uint8(self->out_s, cx - self->rect_cx) else out_uint16_le(self->out_s, cx) self->rect_cx = cx; } if (cy != self->rect_cy) { present |= 0x08; if (order_flags & RDP_ORDER_DELTA) out_uint8(self->out_s, cy - self->rect_cy) else out_uint16_le(self->out_s, cy) self->rect_cy = cy; } if ((color & 0xff) != (self->rect_color & 0xff)) { present |= 0x10; self->rect_color = (self->rect_color & 0xffff00) | (color & 0xff); out_uint8(self->out_s, color); } if ((color & 0xff00) != (self->rect_color & 0xff00)) { present |= 0x20; self->rect_color = (self->rect_color & 0xff00ff) | (color & 0xff00); out_uint8(self->out_s, color >> 8); } if ((color & 0xff0000) != (self->rect_color & 0xff0000)) { present |= 0x40; self->rect_color = (self->rect_color & 0x00ffff) | (color & 0xff0000); out_uint8(self->out_s, color >> 16); } *present_ptr = present; return 0; } /*****************************************************************************/ /* returns error */ /* send a screen blt order */ /* max size 25 */ int xrdp_orders_screen_blt(struct xrdp_orders* self, int x, int y, int cx, int cy, int srcx, int srcy, int rop, struct xrdp_rect* rect) { int order_flags; int vals[12]; int present; char* present_ptr; xrdp_orders_check(self, 25); self->order_count++; order_flags = RDP_ORDER_STANDARD; if (self->last_order != RDP_ORDER_SCREENBLT) order_flags |= RDP_ORDER_CHANGE; self->last_order = RDP_ORDER_SCREENBLT; if (rect != 0) { order_flags |= RDP_ORDER_BOUNDS; if (xrdp_orders_last_bounds(self, rect)) order_flags |= RDP_ORDER_LASTBOUNDS; } vals[0] = x; vals[1] = self->scr_blt_x; vals[2] = y; vals[3] = self->scr_blt_y; vals[4] = cx; vals[5] = self->scr_blt_cx; vals[6] = cy; vals[7] = self->scr_blt_cy; vals[8] = srcx; vals[9] = self->scr_blt_srcx; vals[10] = srcy; vals[11] = self->scr_blt_srcy; if (xrdp_orders_send_delta(self, vals, 12)) order_flags |= RDP_ORDER_DELTA; out_uint8(self->out_s, order_flags); if (order_flags & RDP_ORDER_CHANGE) out_uint8(self->out_s, self->last_order) present = 0; present_ptr = self->out_s->p; /* hold 1 byte present pointer */ out_uint8s(self->out_s, 1) if ((order_flags & RDP_ORDER_BOUNDS) && !(order_flags & RDP_ORDER_LASTBOUNDS)) xrdp_orders_out_bounds(self, rect); if (x != self->scr_blt_x) { present |= 0x01; if (order_flags & RDP_ORDER_DELTA) out_uint8(self->out_s, x - self->scr_blt_x) else out_uint16_le(self->out_s, x) self->scr_blt_x = x; } if (y != self->scr_blt_y) { present |= 0x02; if (order_flags & RDP_ORDER_DELTA) out_uint8(self->out_s, y - self->scr_blt_y) else out_uint16_le(self->out_s, y) self->scr_blt_y = y; } if (cx != self->scr_blt_cx) { present |= 0x04; if (order_flags & RDP_ORDER_DELTA) out_uint8(self->out_s, cx - self->scr_blt_cx) else out_uint16_le(self->out_s, cx) self->scr_blt_cx = cx; } if (cy != self->scr_blt_cy) { present |= 0x08; if (order_flags & RDP_ORDER_DELTA) out_uint8(self->out_s, cy - self->scr_blt_cy) else out_uint16_le(self->out_s, cy) self->scr_blt_cy = cy; } if (rop != self->scr_blt_rop) { present |= 0x10; out_uint8(self->out_s, rop); self->scr_blt_rop = rop; } if (srcx != self->scr_blt_srcx) { present |= 0x20; if (order_flags & RDP_ORDER_DELTA) out_uint8(self->out_s, srcx - self->scr_blt_srcx) else out_uint16_le(self->out_s, srcx) self->scr_blt_srcx = srcx; } if (srcy != self->scr_blt_srcy) { present |= 0x40; if (order_flags & RDP_ORDER_DELTA) out_uint8(self->out_s, srcy - self->scr_blt_srcy) else out_uint16_le(self->out_s, srcy) self->scr_blt_srcy = srcy; } *present_ptr = present; return 0; } /*****************************************************************************/ /* returns error */ /* send a pat blt order */ /* max size 39 */ int xrdp_orders_pat_blt(struct xrdp_orders* self, int x, int y, int cx, int cy, int rop, int bg_color, int fg_color, struct xrdp_brush* brush, struct xrdp_rect* rect) { int order_flags; int vals[8]; int present; char* present_ptr; struct xrdp_brush blank_brush; xrdp_orders_check(self, 39); self->order_count++; order_flags = RDP_ORDER_STANDARD; if (self->last_order != RDP_ORDER_PATBLT) order_flags |= RDP_ORDER_CHANGE; self->last_order = RDP_ORDER_PATBLT; if (rect != 0) { order_flags |= RDP_ORDER_BOUNDS; if (xrdp_orders_last_bounds(self, rect)) order_flags |= RDP_ORDER_LASTBOUNDS; } vals[0] = x; vals[1] = self->pat_blt_x; vals[2] = y; vals[3] = self->pat_blt_y; vals[4] = cx; vals[5] = self->pat_blt_cx; vals[6] = cy; vals[7] = self->pat_blt_cy; if (xrdp_orders_send_delta(self, vals, 8)) order_flags |= RDP_ORDER_DELTA; out_uint8(self->out_s, order_flags); if (order_flags & RDP_ORDER_CHANGE) out_uint8(self->out_s, self->last_order) present = 0; present_ptr = self->out_s->p; /* hold 2 byte present pointer, todo */ out_uint8s(self->out_s, 2) /* this can be smaller, */ /* see RDP_ORDER_SMALL and RDP_ORDER_TINY */ if ((order_flags & RDP_ORDER_BOUNDS) && !(order_flags & RDP_ORDER_LASTBOUNDS)) xrdp_orders_out_bounds(self, rect); if (x != self->pat_blt_x) { present |= 0x0001; if (order_flags & RDP_ORDER_DELTA) out_uint8(self->out_s, x - self->pat_blt_x) else out_uint16_le(self->out_s, x) self->pat_blt_x = x; } if (y != self->pat_blt_y) { present |= 0x0002; if (order_flags & RDP_ORDER_DELTA) out_uint8(self->out_s, y - self->pat_blt_y) else out_uint16_le(self->out_s, y) self->pat_blt_y = y; } if (cx != self->pat_blt_cx) { present |= 0x0004; if (order_flags & RDP_ORDER_DELTA) out_uint8(self->out_s, cx - self->pat_blt_cx) else out_uint16_le(self->out_s, cx) self->pat_blt_cx = cx; } if (cy != self->pat_blt_cy) { present |= 0x0008; if (order_flags & RDP_ORDER_DELTA) out_uint8(self->out_s, cy - self->pat_blt_cy) else out_uint16_le(self->out_s, cy) self->pat_blt_cy = cy; } if (rop != self->pat_blt_rop) { present |= 0x0010; /* PATCOPY PATPAINT PATINVERT DSTINVERT BLACKNESS WHITENESS */ out_uint8(self->out_s, rop); self->pat_blt_rop = rop; } if (bg_color != self->pat_blt_bg_color) { present |= 0x0020; out_uint8(self->out_s, bg_color); out_uint8(self->out_s, bg_color >> 8); out_uint8(self->out_s, bg_color >> 16); self->pat_blt_bg_color = bg_color; } if (fg_color != self->pat_blt_fg_color) { present |= 0x0040; out_uint8(self->out_s, fg_color); out_uint8(self->out_s, fg_color >> 8); out_uint8(self->out_s, fg_color >> 16); self->pat_blt_fg_color = fg_color; } if (brush == 0) /* if nil use blank one */ { /* todo can we just set style to zero */ g_memset(&blank_brush, 0, sizeof(struct xrdp_brush)); brush = &blank_brush; } if (brush->x_orgin != self->pat_blt_brush.x_orgin) { present |= 0x0080; out_uint8(self->out_s, brush->x_orgin); self->pat_blt_brush.x_orgin = brush->x_orgin; } if (brush->y_orgin != self->pat_blt_brush.y_orgin) { present |= 0x0100; out_uint8(self->out_s, brush->y_orgin); self->pat_blt_brush.y_orgin = brush->y_orgin; } if (brush->style != self->pat_blt_brush.style) { present |= 0x0200; out_uint8(self->out_s, brush->style); self->pat_blt_brush.style = brush->style; } if (brush->pattern[0] != self->pat_blt_brush.pattern[0]) { present |= 0x0400; out_uint8(self->out_s, brush->pattern[0]); self->pat_blt_brush.pattern[0] = brush->pattern[0]; } if (g_memcmp(brush->pattern + 1, self->pat_blt_brush.pattern + 1, 7) != 0) { present |= 0x0800; out_uint8a(self->out_s, brush->pattern + 1, 7); g_memcpy(self->pat_blt_brush.pattern + 1, brush->pattern + 1, 7); } *((short*)present_ptr) = present; return 0; } /*****************************************************************************/ /* returns error */ /* send a dest blt order */ /* max size 21 */ int xrdp_orders_dest_blt(struct xrdp_orders* self, int x, int y, int cx, int cy, int rop, struct xrdp_rect* rect) { int order_flags; int vals[8]; int present; char* present_ptr; xrdp_orders_check(self, 21); self->order_count++; order_flags = RDP_ORDER_STANDARD; if (self->last_order != RDP_ORDER_DESTBLT) order_flags |= RDP_ORDER_CHANGE; self->last_order = RDP_ORDER_DESTBLT; if (rect != 0) { order_flags |= RDP_ORDER_BOUNDS; if (xrdp_orders_last_bounds(self, rect)) order_flags |= RDP_ORDER_LASTBOUNDS; } vals[0] = x; vals[1] = self->dest_blt_x; vals[2] = y; vals[3] = self->dest_blt_y; vals[4] = cx; vals[5] = self->dest_blt_cx; vals[6] = cy; vals[7] = self->dest_blt_cy; if (xrdp_orders_send_delta(self, vals, 8)) order_flags |= RDP_ORDER_DELTA; out_uint8(self->out_s, order_flags); if (order_flags & RDP_ORDER_CHANGE) out_uint8(self->out_s, self->last_order) present = 0; present_ptr = self->out_s->p; /* hold 1 byte present pointer */ out_uint8s(self->out_s, 1) if ((order_flags & RDP_ORDER_BOUNDS) && !(order_flags & RDP_ORDER_LASTBOUNDS)) xrdp_orders_out_bounds(self, rect); if (x != self->dest_blt_x) { present |= 0x01; if (order_flags & RDP_ORDER_DELTA) out_uint8(self->out_s, x - self->dest_blt_x) else out_uint16_le(self->out_s, x) self->dest_blt_x = x; } if (y != self->dest_blt_y) { present |= 0x02; if (order_flags & RDP_ORDER_DELTA) out_uint8(self->out_s, y - self->dest_blt_y) else out_uint16_le(self->out_s, y) self->dest_blt_y = y; } if (cx != self->dest_blt_cx) { present |= 0x04; if (order_flags & RDP_ORDER_DELTA) out_uint8(self->out_s, cx - self->dest_blt_cx) else out_uint16_le(self->out_s, cx) self->dest_blt_cx = cx; } if (cy != self->dest_blt_cy) { present |= 0x08; if (order_flags & RDP_ORDER_DELTA) out_uint8(self->out_s, cy - self->dest_blt_cy) else out_uint16_le(self->out_s, cy) self->dest_blt_cy = cy; } if (rop != self->dest_blt_rop) { present |= 0x0010; out_uint8(self->out_s, rop); self->dest_blt_rop = rop; } *present_ptr = present; return 0; } /*****************************************************************************/ /* returns error */ /* send a line order */ /* max size 32 */ int xrdp_orders_line(struct xrdp_orders* self, int mix_mode, int startx, int starty, int endx, int endy, int rop, int bg_color, struct xrdp_pen* pen, struct xrdp_rect* rect) { int order_flags; int vals[8]; int present; char* present_ptr; struct xrdp_pen blank_pen; xrdp_orders_check(self, 32); self->order_count++; order_flags = RDP_ORDER_STANDARD; if (self->last_order != RDP_ORDER_LINE) order_flags |= RDP_ORDER_CHANGE; self->last_order = RDP_ORDER_LINE; if (rect != 0) { order_flags |= RDP_ORDER_BOUNDS; if (xrdp_orders_last_bounds(self, rect)) order_flags |= RDP_ORDER_LASTBOUNDS; } vals[0] = startx; vals[1] = self->line_startx; vals[2] = starty; vals[3] = self->line_starty; vals[4] = endx; vals[5] = self->line_endx; vals[6] = endy; vals[7] = self->line_endy; if (xrdp_orders_send_delta(self, vals, 8)) order_flags |= RDP_ORDER_DELTA; out_uint8(self->out_s, order_flags); if (order_flags & RDP_ORDER_CHANGE) out_uint8(self->out_s, self->last_order) present = 0; present_ptr = self->out_s->p; /* hold 2 byte present pointer */ out_uint8s(self->out_s, 2) if ((order_flags & RDP_ORDER_BOUNDS) && !(order_flags & RDP_ORDER_LASTBOUNDS)) xrdp_orders_out_bounds(self, rect); if (mix_mode != self->line_mix_mode) { present |= 0x0001; out_uint16_le(self->out_s, mix_mode) self->line_mix_mode = mix_mode; } if (startx != self->line_startx) { present |= 0x0002; if (order_flags & RDP_ORDER_DELTA) out_uint8(self->out_s, startx - self->line_startx) else out_uint16_le(self->out_s, startx) self->line_startx = startx; } if (starty != self->line_starty) { present |= 0x0004; if (order_flags & RDP_ORDER_DELTA) out_uint8(self->out_s, starty - self->line_starty) else out_uint16_le(self->out_s, starty) self->line_starty = starty; } if (endx != self->line_endx) { present |= 0x0008; if (order_flags & RDP_ORDER_DELTA) out_uint8(self->out_s, endx - self->line_endx) else out_uint16_le(self->out_s, endx) self->line_endx = endx; } if (endy != self->line_endy) { present |= 0x0010; if (order_flags & RDP_ORDER_DELTA) out_uint8(self->out_s, endy - self->line_endy) else out_uint16_le(self->out_s, endy) self->line_endy = endy; } if (bg_color != self->line_bg_color) { present |= 0x0020; out_uint8(self->out_s, bg_color) out_uint8(self->out_s, bg_color >> 8) out_uint8(self->out_s, bg_color >> 16) self->line_bg_color = bg_color; } if (rop != self->line_rop) { present |= 0x0040; out_uint8(self->out_s, rop) self->line_rop = rop; } if (pen == 0) { g_memset(&blank_pen, 0, sizeof(struct xrdp_pen)); pen = &blank_pen; } if (pen->style != self->line_pen.style) { present |= 0x0080; out_uint8(self->out_s, pen->style) self->line_pen.style = pen->style; } if (pen->width != self->line_pen.width) { present |= 0x0100; out_uint8(self->out_s, pen->width) self->line_pen.width = pen->width; } if (pen->color != self->line_pen.color) { present |= 0x0200; out_uint8(self->out_s, pen->color) out_uint8(self->out_s, pen->color >> 8) out_uint8(self->out_s, pen->color >> 16) self->line_pen.color = pen->color; } *((short*)present_ptr) = present; return 0; } /*****************************************************************************/ /* returns error */ /* send a mem blt order */ /* max size 30 */ int xrdp_orders_mem_blt(struct xrdp_orders* self, int cache_id, int color_table, int x, int y, int cx, int cy, int rop, int srcx, int srcy, int cache_idx, struct xrdp_rect* rect) { int order_flags; int vals[12]; int present; char* present_ptr; xrdp_orders_check(self, 30); self->order_count++; order_flags = RDP_ORDER_STANDARD; if (self->last_order != RDP_ORDER_MEMBLT) order_flags |= RDP_ORDER_CHANGE; self->last_order = RDP_ORDER_MEMBLT; if (rect != 0) { order_flags |= RDP_ORDER_BOUNDS; if (xrdp_orders_last_bounds(self, rect)) order_flags |= RDP_ORDER_LASTBOUNDS; } vals[0] = x; vals[1] = self->mem_blt_x; vals[2] = y; vals[3] = self->mem_blt_y; vals[4] = cx; vals[5] = self->mem_blt_cx; vals[6] = cy; vals[7] = self->mem_blt_cy; vals[8] = srcx; vals[9] = self->mem_blt_srcx; vals[10] = srcy; vals[11] = self->mem_blt_srcy; if (xrdp_orders_send_delta(self, vals, 12)) order_flags |= RDP_ORDER_DELTA; out_uint8(self->out_s, order_flags); if (order_flags & RDP_ORDER_CHANGE) out_uint8(self->out_s, self->last_order) present = 0; present_ptr = self->out_s->p; /* hold 2 byte present pointer, todo */ out_uint8s(self->out_s, 2) /* this can be smaller, */ /* see RDP_ORDER_SMALL and RDP_ORDER_TINY */ if ((order_flags & RDP_ORDER_BOUNDS) && !(order_flags & RDP_ORDER_LASTBOUNDS)) xrdp_orders_out_bounds(self, rect); if (cache_id != self->mem_blt_cache_id || color_table != self->mem_blt_color_table) { present |= 0x0001; out_uint8(self->out_s, cache_id); out_uint8(self->out_s, color_table); self->mem_blt_cache_id = cache_id; self->mem_blt_color_table = color_table; } if (x != self->mem_blt_x) { present |= 0x0002; if (order_flags & RDP_ORDER_DELTA) out_uint8(self->out_s, x - self->mem_blt_x) else out_uint16_le(self->out_s, x) self->mem_blt_x = x; } if (y != self->mem_blt_y) { present |= 0x0004; if (order_flags & RDP_ORDER_DELTA) out_uint8(self->out_s, y - self->mem_blt_y) else out_uint16_le(self->out_s, y) self->mem_blt_y = y; } if (cx != self->mem_blt_cx) { present |= 0x0008; if (order_flags & RDP_ORDER_DELTA) out_uint8(self->out_s, cx - self->mem_blt_cx) else out_uint16_le(self->out_s, cx) self->mem_blt_cx = cx; } if (cy != self->mem_blt_cy) { present |= 0x0010; if (order_flags & RDP_ORDER_DELTA) out_uint8(self->out_s, cy - self->mem_blt_cy) else out_uint16_le(self->out_s, cy) self->mem_blt_cy = cy; } if (rop != self->mem_blt_rop) { present |= 0x0020; out_uint8(self->out_s, rop); self->mem_blt_rop = rop; } if (srcx != self->mem_blt_srcx) { present |= 0x0040; if (order_flags & RDP_ORDER_DELTA) out_uint8(self->out_s, srcx - self->mem_blt_srcx) else out_uint16_le(self->out_s, srcx) self->mem_blt_srcx = srcx; } if (srcy != self->mem_blt_srcy) { present |= 0x0080; if (order_flags & RDP_ORDER_DELTA) out_uint8(self->out_s, srcy - self->mem_blt_srcy) else out_uint16_le(self->out_s, srcy) self->mem_blt_srcy = srcy; } if (cache_idx != self->mem_blt_cache_idx) { present |= 0x0100; out_uint16_le(self->out_s, cache_idx); self->mem_blt_cache_idx = cache_idx; } *((short*)present_ptr) = present; return 0; } /*****************************************************************************/ /* returns error */ /* when a palette gets sent, send the main palette too */ int xrdp_orders_send_palette(struct xrdp_orders* self, int* palette, int cache_id) { int order_flags; int len; int i; xrdp_wm_send_palette(self->pro_layer->wm); xrdp_orders_check(self, 2000); self->order_count++; order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; out_uint8(self->out_s, order_flags); len = 1027 - 7; /* length after type minus 7 */ out_uint16_le(self->out_s, len); out_uint16_le(self->out_s, 0); /* flags */ out_uint8(self->out_s, RDP_ORDER_COLCACHE); /* type */ out_uint8(self->out_s, cache_id); out_uint16_le(self->out_s, 256); /* num colors */ for (i = 0; i < 256; i++) { out_uint8(self->out_s, palette[i]); out_uint8(self->out_s, palette[i] >> 8); out_uint8(self->out_s, palette[i] >> 16); out_uint8(self->out_s, 0); } return 0; } /*****************************************************************************/ /* returns error */ /* max size width * height * Bpp + 16 */ int xrdp_orders_send_raw_bitmap(struct xrdp_orders* self, struct xrdp_bitmap* bitmap, int cache_id, int cache_idx) { int order_flags; int len; int bufsize; int Bpp; int i; int j; int pixel; Bpp = (bitmap->bpp + 7) / 8; bufsize = bitmap->width * bitmap->height * Bpp; xrdp_orders_check(self, bufsize + 16); self->order_count++; order_flags = RDP_ORDER_STANDARD | RDP_ORDER_SECONDARY; out_uint8(self->out_s, order_flags); len = (bufsize + 9) - 7; out_uint16_le(self->out_s, len); out_uint16_le(self->out_s, 8); /* flags */ out_uint8(self->out_s, RDP_ORDER_RAW_BMPCACHE); /* type */ out_uint8(self->out_s, cache_id); out_uint8s(self->out_s, 1); /* pad */ out_uint8(self->out_s, bitmap->width); out_uint8(self->out_s, bitmap->height); out_uint8(self->out_s, bitmap->bpp); out_uint16_le(self->out_s, bufsize); out_uint16_le(self->out_s, cache_idx); for (i = bitmap->height - 1; i >= 0; i--) for (j = 0; j < bitmap->width; j++) { pixel = xrdp_bitmap_get_pixel(bitmap, j, i); if (Bpp == 3) { out_uint8(self->out_s, pixel >> 16); out_uint8(self->out_s, pixel >> 8); out_uint8(self->out_s, pixel); } else if (Bpp == 2) { out_uint8(self->out_s, pixel); out_uint8(self->out_s, pixel >> 8); } else if (Bpp == 1) out_uint8(self->out_s, pixel); } return 0; }