/** * xrdp: A Remote Desktop Protocol server. * * Copyright (C) Jay Sorg 2004-2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ibrdp orders */ #include "rdp.h" #ifndef NULL #define NULL 0 #endif /*****************************************************************************/ struct rdp_orders *APP_CC rdp_orders_create(struct rdp_rdp *owner) { struct rdp_orders *self = (struct rdp_orders *)NULL; self = (struct rdp_orders *)g_malloc(sizeof(struct rdp_orders), 1); self->rdp_layer = owner; return self; } /*****************************************************************************/ void APP_CC rdp_orders_delete(struct rdp_orders *self) { int i = 0; int j = 0; if (self == 0) { return; } /* free the colormap cache */ for (i = 0; i < 6; i++) { g_free(self->cache_colormap[i]); } /* free the bitmap cache */ for (i = 0; i < 3; i++) { for (j = 0; j < 600; j++) { if (self->cache_bitmap[i][j] != 0) { g_free(self->cache_bitmap[i][j]->data); } g_free(self->cache_bitmap[i][j]); } } g_free(self); } /*****************************************************************************/ void APP_CC rdp_orders_reset_state(struct rdp_orders *self) { g_memset(&self->state, 0, sizeof(self->state)); } /*****************************************************************************/ /* Read field indicating which parameters are present */ static void APP_CC rdp_orders_in_present(struct stream *s, int *present, int flags, int size) { int bits = 0; int i = 0; if (flags & RDP_ORDER_SMALL) { size--; } if (flags & RDP_ORDER_TINY) { if (size < 2) { size = 0; } else { size -= 2; } } *present = 0; for (i = 0; i < size; i++) { in_uint8(s, bits); *present |= bits << (i * 8); } } /*****************************************************************************/ /* Read a co-ordinate (16-bit, or 8-bit delta) */ static void APP_CC rdp_orders_in_coord(struct stream *s, int *coord, int delta) { int change = 0; if (delta) { in_sint8(s, change); *coord += change; } else { in_sint16_le(s, *coord); } } /*****************************************************************************/ /* Parse bounds information */ static void APP_CC rdp_orders_parse_bounds(struct rdp_orders *self, struct stream *s) { int present = 0; in_uint8(s, present); if (present & 1) { rdp_orders_in_coord(s, &self->state.clip_left, 0); } else if (present & 16) { rdp_orders_in_coord(s, &self->state.clip_left, 1); } if (present & 2) { rdp_orders_in_coord(s, &self->state.clip_top, 0); } else if (present & 32) { rdp_orders_in_coord(s, &self->state.clip_top, 1); } if (present & 4) { rdp_orders_in_coord(s, &self->state.clip_right, 0); } else if (present & 64) { rdp_orders_in_coord(s, &self->state.clip_right, 1); } if (present & 8) { rdp_orders_in_coord(s, &self->state.clip_bottom, 0); } else if (present & 128) { rdp_orders_in_coord(s, &self->state.clip_bottom, 1); } } /*****************************************************************************/ /* Process a colormap cache order */ static void APP_CC rdp_orders_process_colcache(struct rdp_orders *self, struct stream *s, int flags) { struct rdp_colormap *colormap = (struct rdp_colormap *)NULL; struct stream *rec_s = (struct stream *)NULL; int cache_id = 0; int i = 0; colormap = (struct rdp_colormap *)g_malloc(sizeof(struct rdp_colormap), 1); in_uint8(s, cache_id); in_uint16_le(s, colormap->ncolors); for (i = 0; i < colormap->ncolors; i++) { in_uint32_le(s, colormap->colors[i]); } g_free(self->cache_colormap[cache_id]); self->cache_colormap[cache_id] = colormap; if (self->rdp_layer->rec_mode) { rdp_rec_check_file(self->rdp_layer); make_stream(rec_s); init_stream(rec_s, 4096); s_push_layer(rec_s, iso_hdr, 4); out_uint8(rec_s, 10); out_uint8(rec_s, cache_id); for (i = 0; i < 256; i++) { out_uint32_le(rec_s, colormap->colors[i]); } rdp_rec_write_item(self->rdp_layer, rec_s); free_stream(rec_s); } } /*****************************************************************************/ /* Process a raw bitmap cache order */ static void APP_CC rdp_orders_process_raw_bmpcache(struct rdp_orders *self, struct stream *s, int flags) { int cache_idx = 0; int cache_id = 0; int width = 0; int height = 0; int bpp = 0; int Bpp = 0; int x = 0; int y = 0; char *inverted = (char *)NULL; char *dst = (char *)NULL; struct rdp_bitmap *bitmap = (struct rdp_bitmap *)NULL; struct stream *rec_s = (struct stream *)NULL; in_uint8(s, cache_id); in_uint8s(s, 1); in_uint8(s, width); in_uint8(s, height); in_uint8(s, bpp); Bpp = (bpp + 7) / 8; in_uint8s(s, 2); /* bufsize */ in_uint16_le(s, cache_idx); inverted = (char *)g_malloc(width * height * Bpp, 0); for (y = 0; y < height; y++) { dst = inverted + (((height - y) - 1) * (width * Bpp)); if (Bpp == 1) { for (x = 0; x < width; x++) { in_uint8(s, dst[x]); } } else if (Bpp == 2) { for (x = 0; x < width; x++) { in_uint16_le(s, ((tui16 *)dst)[x]); } } else if (Bpp == 3) { for (x = 0; x < width; x++) { in_uint8(s, dst[x * 3 + 0]); in_uint8(s, dst[x * 3 + 1]); in_uint8(s, dst[x * 3 + 2]); } } } bitmap = (struct rdp_bitmap *)g_malloc(sizeof(struct rdp_bitmap), 0); bitmap->width = width; bitmap->height = height; bitmap->bpp = bpp; bitmap->data = inverted; if (self->cache_bitmap[cache_id][cache_idx] != 0) { g_free(self->cache_bitmap[cache_id][cache_idx]->data); } g_free(self->cache_bitmap[cache_id][cache_idx]); self->cache_bitmap[cache_id][cache_idx] = bitmap; if (self->rdp_layer->rec_mode) { y = width * height * Bpp; rdp_rec_check_file(self->rdp_layer); make_stream(rec_s); init_stream(rec_s, y + 256); s_push_layer(rec_s, iso_hdr, 4); out_uint8(rec_s, 8); out_uint8(rec_s, cache_id); out_uint16_le(rec_s, cache_idx); out_uint16_le(rec_s, width); out_uint16_le(rec_s, height); out_uint16_le(rec_s, y); out_uint8a(rec_s, inverted, y); rdp_rec_write_item(self->rdp_layer, rec_s); free_stream(rec_s); } } /*****************************************************************************/ /* Process a bitmap cache order */ static void APP_CC rdp_orders_process_bmpcache(struct rdp_orders *self, struct stream *s, int flags) { char *data = (char *)NULL; char *bmpdata = (char *)NULL; int cache_idx = 0; int size = 0; int cache_id = 0; int width = 0; int height = 0; int bpp = 0; int Bpp = 0; int bufsize = 0; struct rdp_bitmap *bitmap = (struct rdp_bitmap *)NULL; struct stream *rec_s = (struct stream *)NULL; in_uint8(s, cache_id); in_uint8s(s, 1); /* pad */ in_uint8(s, width); in_uint8(s, height); in_uint8(s, bpp); Bpp = (bpp + 7) / 8; in_uint16_le(s, bufsize); in_uint16_le(s, cache_idx); if (flags & 1024) { size = bufsize; } else { in_uint8s(s, 2); /* pad */ in_uint16_le(s, size); in_uint8s(s, 2); /* row_size */ in_uint8s(s, 2); /* final_size */ } in_uint8p(s, data, size); bmpdata = (char *)g_malloc(width * height * Bpp, 0); if (rdp_bitmap_decompress(bmpdata, width, height, data, size, Bpp)) { } else { /* error */ } bitmap = (struct rdp_bitmap *)g_malloc(sizeof(struct rdp_bitmap), 0); bitmap->width = width; bitmap->height = height; bitmap->bpp = bpp; bitmap->data = bmpdata; if (self->cache_bitmap[cache_id][cache_idx] != 0) { g_free(self->cache_bitmap[cache_id][cache_idx]->data); } g_free(self->cache_bitmap[cache_id][cache_idx]); self->cache_bitmap[cache_id][cache_idx] = bitmap; if (self->rdp_layer->rec_mode) { size = width * height * Bpp; rdp_rec_check_file(self->rdp_layer); make_stream(rec_s); init_stream(rec_s, size + 256); s_push_layer(rec_s, iso_hdr, 4); out_uint8(rec_s, 8); out_uint8(rec_s, cache_id); out_uint16_le(rec_s, cache_idx); out_uint16_le(rec_s, width); out_uint16_le(rec_s, height); out_uint16_le(rec_s, size); out_uint8a(rec_s, bmpdata, size); rdp_rec_write_item(self->rdp_layer, rec_s); free_stream(rec_s); } } /*****************************************************************************/ /* Process a font cache order */ static void APP_CC rdp_orders_process_fontcache(struct rdp_orders *self, struct stream *s, int flags) { struct stream *rec_s = (struct stream *)NULL; int font = 0; int nglyphs = 0; int character = 0; int offset = 0; int baseline = 0; int width = 0; int height = 0; int i = 0; int datasize = 0; char *data = (char *)NULL; in_uint8(s, font); in_uint8(s, nglyphs); for (i = 0; i < nglyphs; i++) { in_uint16_le(s, character); in_uint16_le(s, offset); in_uint16_le(s, baseline); in_uint16_le(s, width); in_uint16_le(s, height); datasize = (height * ((width + 7) / 8) + 3) & ~3; in_uint8p(s, data, datasize); self->rdp_layer->mod->server_add_char(self->rdp_layer->mod, font, character, offset, baseline, width, height, data); if (self->rdp_layer->rec_mode) { rdp_rec_check_file(self->rdp_layer); make_stream(rec_s); init_stream(rec_s, datasize + 256); s_push_layer(rec_s, iso_hdr, 4); out_uint8(rec_s, 9); out_uint8(rec_s, font); out_uint16_le(rec_s, character); out_uint16_le(rec_s, offset); out_uint16_le(rec_s, baseline); out_uint16_le(rec_s, width); out_uint16_le(rec_s, height); out_uint16_le(rec_s, datasize); out_uint8a(rec_s, data, datasize); rdp_rec_write_item(self->rdp_layer, rec_s); free_stream(rec_s); } } } /*****************************************************************************/ /* Process a secondary order */ static int APP_CC rdp_orders_process_secondary_order(struct rdp_orders *self, struct stream *s) { short length = 0; int flags = 0; int type = 0; char *next_order = (char *)NULL; in_uint16_le(s, length); in_uint16_le(s, flags); in_uint8(s, type); next_order = s->p + length + 7; switch (type) { case RDP_ORDER_COLCACHE: rdp_orders_process_colcache(self, s, flags); break; case RDP_ORDER_RAW_BMPCACHE: rdp_orders_process_raw_bmpcache(self, s, flags); break; case RDP_ORDER_BMPCACHE: rdp_orders_process_bmpcache(self, s, flags); break; case RDP_ORDER_FONTCACHE: rdp_orders_process_fontcache(self, s, flags); break; default: /* error, unknown order */ break; } s->p = next_order; return 0; } /*****************************************************************************/ /* Read a color entry */ static void APP_CC rdp_orders_in_color(struct stream *s, int *color) { int i = 0; in_uint8(s, i); *color = i; in_uint8(s, i); *color |= i << 8; in_uint8(s, i); *color |= i << 16; } /*****************************************************************************/ /* Parse a brush */ static void APP_CC rdp_orders_parse_brush(struct stream *s, struct rdp_brush *brush, int present) { if (present & 1) { in_uint8(s, brush->xorigin); } if (present & 2) { in_uint8(s, brush->yorigin); } if (present & 4) { in_uint8(s, brush->style); } if (present & 8) { in_uint8(s, brush->pattern[0]); } if (present & 16) { in_uint8a(s, brush->pattern + 1, 7); } } /*****************************************************************************/ /* Parse a pen */ static void APP_CC rdp_orders_parse_pen(struct stream *s, struct rdp_pen *pen, int present) { if (present & 1) { in_uint8(s, pen->style); } if (present & 2) { in_uint8(s, pen->width); } if (present & 4) { rdp_orders_in_color(s, &pen->color); } } /*****************************************************************************/ /* Process a text order */ static void APP_CC rdp_orders_process_text2(struct rdp_orders *self, struct stream *s, int present, int delta) { int fgcolor = 0; int bgcolor = 0; struct stream *rec_s = (struct stream *)NULL; if (present & 0x000001) { in_uint8(s, self->state.text_font); } if (present & 0x000002) { in_uint8(s, self->state.text_flags); } if (present & 0x000004) { in_uint8(s, self->state.text_opcode); } if (present & 0x000008) { in_uint8(s, self->state.text_mixmode); } if (present & 0x000010) { rdp_orders_in_color(s, &self->state.text_fgcolor); } if (present & 0x000020) { rdp_orders_in_color(s, &self->state.text_bgcolor); } if (present & 0x000040) { in_sint16_le(s, self->state.text_clipleft); } if (present & 0x000080) { in_sint16_le(s, self->state.text_cliptop); } if (present & 0x000100) { in_sint16_le(s, self->state.text_clipright); } if (present & 0x000200) { in_sint16_le(s, self->state.text_clipbottom); } if (present & 0x000400) { in_sint16_le(s, self->state.text_boxleft); } if (present & 0x000800) { in_sint16_le(s, self->state.text_boxtop); } if (present & 0x001000) { in_sint16_le(s, self->state.text_boxright); } if (present & 0x002000) { in_sint16_le(s, self->state.text_boxbottom); } rdp_orders_parse_brush(s, &self->state.text_brush, present >> 14); if (present & 0x080000) { in_sint16_le(s, self->state.text_x); } if (present & 0x100000) { in_sint16_le(s, self->state.text_y); } if (present & 0x200000) { in_uint8(s, self->state.text_length); in_uint8a(s, self->state.text_text, self->state.text_length); } self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, self->state.text_opcode); fgcolor = rdp_orders_convert_color(self->rdp_layer->mod->rdp_bpp, self->rdp_layer->mod->xrdp_bpp, self->state.text_fgcolor, self->rdp_layer->colormap.colors); self->rdp_layer->mod->server_set_fgcolor(self->rdp_layer->mod, fgcolor); bgcolor = rdp_orders_convert_color(self->rdp_layer->mod->rdp_bpp, self->rdp_layer->mod->xrdp_bpp, self->state.text_bgcolor, self->rdp_layer->colormap.colors); self->rdp_layer->mod->server_set_bgcolor(self->rdp_layer->mod, bgcolor); self->rdp_layer->mod->server_draw_text(self->rdp_layer->mod, self->state.text_font, self->state.text_flags, self->state.text_mixmode, self->state.text_clipleft, self->state.text_cliptop, self->state.text_clipright, self->state.text_clipbottom, self->state.text_boxleft, self->state.text_boxtop, self->state.text_boxright, self->state.text_boxbottom, self->state.text_x, self->state.text_y, self->state.text_text, self->state.text_length); self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, 0xcc); if (self->rdp_layer->rec_mode) { rdp_rec_check_file(self->rdp_layer); make_stream(rec_s); init_stream(rec_s, 512); s_push_layer(rec_s, iso_hdr, 4); out_uint8(rec_s, 7); out_uint8(rec_s, self->state.text_font); out_uint8(rec_s, self->state.text_flags); out_uint8(rec_s, self->state.text_opcode); out_uint8(rec_s, self->state.text_mixmode); out_uint32_le(rec_s, self->state.text_fgcolor); out_uint32_le(rec_s, self->state.text_bgcolor); out_uint16_le(rec_s, self->state.text_clipleft); out_uint16_le(rec_s, self->state.text_cliptop); out_uint16_le(rec_s, self->state.text_clipright); out_uint16_le(rec_s, self->state.text_clipbottom); out_uint16_le(rec_s, self->state.text_boxleft); out_uint16_le(rec_s, self->state.text_boxtop); out_uint16_le(rec_s, self->state.text_boxright); out_uint16_le(rec_s, self->state.text_boxbottom); out_uint16_le(rec_s, self->state.text_x); out_uint16_le(rec_s, self->state.text_y); out_uint16_le(rec_s, self->state.text_length); out_uint8a(rec_s, self->state.text_text, self->state.text_length); rdp_rec_write_item(self->rdp_layer, rec_s); free_stream(rec_s); } } /*****************************************************************************/ /* Process a destination blt order */ static void APP_CC rdp_orders_process_destblt(struct rdp_orders *self, struct stream *s, int present, int delta) { struct stream *rec_s = (struct stream *)NULL; if (present & 0x01) { rdp_orders_in_coord(s, &self->state.dest_x, delta); } if (present & 0x02) { rdp_orders_in_coord(s, &self->state.dest_y, delta); } if (present & 0x04) { rdp_orders_in_coord(s, &self->state.dest_cx, delta); } if (present & 0x08) { rdp_orders_in_coord(s, &self->state.dest_cy, delta); } if (present & 0x10) { in_uint8(s, self->state.dest_opcode); } self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, self->state.dest_opcode); self->rdp_layer->mod->server_fill_rect(self->rdp_layer->mod, self->state.dest_x, self->state.dest_y, self->state.dest_cx, self->state.dest_cy); self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, 0xcc); if (self->rdp_layer->rec_mode) { rdp_rec_check_file(self->rdp_layer); make_stream(rec_s); init_stream(rec_s, 512); s_push_layer(rec_s, iso_hdr, 4); out_uint8(rec_s, 6); out_uint16_le(rec_s, self->state.dest_x); out_uint16_le(rec_s, self->state.dest_y); out_uint16_le(rec_s, self->state.dest_cx); out_uint16_le(rec_s, self->state.dest_cy); out_uint8(rec_s, self->state.dest_opcode); rdp_rec_write_item(self->rdp_layer, rec_s); free_stream(rec_s); } } /*****************************************************************************/ /* Process a pattern blt order */ static void APP_CC rdp_orders_process_patblt(struct rdp_orders *self, struct stream *s, int present, int delta) { int fgcolor = 0; int bgcolor = 0; struct stream *rec_s = (struct stream *)NULL; if (present & 0x0001) { rdp_orders_in_coord(s, &self->state.pat_x, delta); } if (present & 0x0002) { rdp_orders_in_coord(s, &self->state.pat_y, delta); } if (present & 0x0004) { rdp_orders_in_coord(s, &self->state.pat_cx, delta); } if (present & 0x0008) { rdp_orders_in_coord(s, &self->state.pat_cy, delta); } if (present & 0x0010) { in_uint8(s, self->state.pat_opcode); } if (present & 0x0020) { rdp_orders_in_color(s, &self->state.pat_bgcolor); } if (present & 0x0040) { rdp_orders_in_color(s, &self->state.pat_fgcolor); } rdp_orders_parse_brush(s, &self->state.pat_brush, present >> 7); self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, self->state.pat_opcode); self->rdp_layer->mod->server_set_mixmode(self->rdp_layer->mod, 1); fgcolor = rdp_orders_convert_color(self->rdp_layer->mod->rdp_bpp, self->rdp_layer->mod->xrdp_bpp, self->state.pat_fgcolor, self->rdp_layer->colormap.colors); self->rdp_layer->mod->server_set_fgcolor(self->rdp_layer->mod, fgcolor); bgcolor = rdp_orders_convert_color(self->rdp_layer->mod->rdp_bpp, self->rdp_layer->mod->xrdp_bpp, self->state.pat_bgcolor, self->rdp_layer->colormap.colors); self->rdp_layer->mod->server_set_bgcolor(self->rdp_layer->mod, bgcolor); self->rdp_layer->mod->server_set_brush(self->rdp_layer->mod, self->state.pat_brush.xorigin, self->state.pat_brush.yorigin, self->state.pat_brush.style, self->state.pat_brush.pattern); self->rdp_layer->mod->server_fill_rect(self->rdp_layer->mod, self->state.pat_x, self->state.pat_y, self->state.pat_cx, self->state.pat_cy); self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, 0xcc); self->rdp_layer->mod->server_set_mixmode(self->rdp_layer->mod, 0); if (self->rdp_layer->rec_mode) { rdp_rec_check_file(self->rdp_layer); make_stream(rec_s); init_stream(rec_s, 512); s_push_layer(rec_s, iso_hdr, 4); out_uint8(rec_s, 5); out_uint16_le(rec_s, self->state.pat_x); out_uint16_le(rec_s, self->state.pat_y); out_uint16_le(rec_s, self->state.pat_cx); out_uint16_le(rec_s, self->state.pat_cy); out_uint8(rec_s, self->state.pat_opcode); out_uint32_le(rec_s, self->state.pat_fgcolor); out_uint32_le(rec_s, self->state.pat_bgcolor); out_uint8(rec_s, self->state.pat_brush.xorigin); out_uint8(rec_s, self->state.pat_brush.yorigin); out_uint8(rec_s, self->state.pat_brush.style); out_uint8a(rec_s, self->state.pat_brush.pattern, 8); rdp_rec_write_item(self->rdp_layer, rec_s); free_stream(rec_s); } } /*****************************************************************************/ /* Process a screen blt order */ static void APP_CC rdp_orders_process_screenblt(struct rdp_orders *self, struct stream *s, int present, int delta) { struct stream *rec_s; if (present & 0x0001) { rdp_orders_in_coord(s, &self->state.screenblt_x, delta); } if (present & 0x0002) { rdp_orders_in_coord(s, &self->state.screenblt_y, delta); } if (present & 0x0004) { rdp_orders_in_coord(s, &self->state.screenblt_cx, delta); } if (present & 0x0008) { rdp_orders_in_coord(s, &self->state.screenblt_cy, delta); } if (present & 0x0010) { in_uint8(s, self->state.screenblt_opcode); } if (present & 0x0020) { rdp_orders_in_coord(s, &self->state.screenblt_srcx, delta); } if (present & 0x0040) { rdp_orders_in_coord(s, &self->state.screenblt_srcy, delta); } self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, self->state.screenblt_opcode); self->rdp_layer->mod->server_screen_blt(self->rdp_layer->mod, self->state.screenblt_x, self->state.screenblt_y, self->state.screenblt_cx, self->state.screenblt_cy, self->state.screenblt_srcx, self->state.screenblt_srcy); self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, 0xcc); if (self->rdp_layer->rec_mode) { rdp_rec_check_file(self->rdp_layer); make_stream(rec_s); init_stream(rec_s, 512); s_push_layer(rec_s, iso_hdr, 4); out_uint8(rec_s, 4); out_uint16_le(rec_s, self->state.screenblt_x); out_uint16_le(rec_s, self->state.screenblt_y); out_uint16_le(rec_s, self->state.screenblt_cx); out_uint16_le(rec_s, self->state.screenblt_cy); out_uint16_le(rec_s, self->state.screenblt_srcx); out_uint16_le(rec_s, self->state.screenblt_srcy); out_uint8(rec_s, self->state.screenblt_opcode); rdp_rec_write_item(self->rdp_layer, rec_s); free_stream(rec_s); } } /*****************************************************************************/ /* Process a line order */ static void APP_CC rdp_orders_process_line(struct rdp_orders *self, struct stream *s, int present, int delta) { int bgcolor = 0; int fgcolor = 0; struct stream *rec_s = (struct stream *)NULL; if (present & 0x0001) { in_uint16_le(s, self->state.line_mixmode); } if (present & 0x0002) { rdp_orders_in_coord(s, &self->state.line_startx, delta); } if (present & 0x0004) { rdp_orders_in_coord(s, &self->state.line_starty, delta); } if (present & 0x0008) { rdp_orders_in_coord(s, &self->state.line_endx, delta); } if (present & 0x0010) { rdp_orders_in_coord(s, &self->state.line_endy, delta); } if (present & 0x0020) { rdp_orders_in_color(s, &self->state.line_bgcolor); } if (present & 0x0040) { in_uint8(s, self->state.line_opcode); } rdp_orders_parse_pen(s, &self->state.line_pen, present >> 7); self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, self->state.line_opcode); bgcolor = rdp_orders_convert_color(self->rdp_layer->mod->rdp_bpp, self->rdp_layer->mod->xrdp_bpp, self->state.line_bgcolor, self->rdp_layer->colormap.colors); fgcolor = rdp_orders_convert_color(self->rdp_layer->mod->rdp_bpp, self->rdp_layer->mod->xrdp_bpp, self->state.line_pen.color, self->rdp_layer->colormap.colors); self->rdp_layer->mod->server_set_fgcolor(self->rdp_layer->mod, fgcolor); self->rdp_layer->mod->server_set_bgcolor(self->rdp_layer->mod, bgcolor); self->rdp_layer->mod->server_set_pen(self->rdp_layer->mod, self->state.line_pen.style, self->state.line_pen.width); self->rdp_layer->mod->server_draw_line(self->rdp_layer->mod, self->state.line_startx, self->state.line_starty, self->state.line_endx, self->state.line_endy); self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, 0xcc); if (self->rdp_layer->rec_mode) { rdp_rec_check_file(self->rdp_layer); make_stream(rec_s); init_stream(rec_s, 512); s_push_layer(rec_s, iso_hdr, 4); out_uint8(rec_s, 3); out_uint16_le(rec_s, self->state.line_mixmode); out_uint16_le(rec_s, self->state.line_startx); out_uint16_le(rec_s, self->state.line_starty); out_uint16_le(rec_s, self->state.line_endx); out_uint16_le(rec_s, self->state.line_endy); out_uint32_le(rec_s, self->state.line_bgcolor); out_uint8(rec_s, self->state.line_opcode); out_uint8(rec_s, self->state.line_pen.style); out_uint8(rec_s, self->state.line_pen.width); out_uint32_le(rec_s, self->state.line_pen.color); rdp_rec_write_item(self->rdp_layer, rec_s); free_stream(rec_s); } } /*****************************************************************************/ /* Process an opaque rectangle order */ static void APP_CC rdp_orders_process_rect(struct rdp_orders *self, struct stream *s, int present, int delta) { int i = 0; int fgcolor = 0; struct stream *rec_s = (struct stream *)NULL; if (present & 0x01) { rdp_orders_in_coord(s, &self->state.rect_x, delta); } if (present & 0x02) { rdp_orders_in_coord(s, &self->state.rect_y, delta); } if (present & 0x04) { rdp_orders_in_coord(s, &self->state.rect_cx, delta); } if (present & 0x08) { rdp_orders_in_coord(s, &self->state.rect_cy, delta); } if (present & 0x10) { in_uint8(s, i); self->state.rect_color = (self->state.rect_color & 0xffffff00) | i; } if (present & 0x20) { in_uint8(s, i); self->state.rect_color = (self->state.rect_color & 0xffff00ff) | (i << 8); } if (present & 0x40) { in_uint8(s, i); self->state.rect_color = (self->state.rect_color & 0xff00ffff) | (i << 16); } fgcolor = rdp_orders_convert_color(self->rdp_layer->mod->rdp_bpp, self->rdp_layer->mod->xrdp_bpp, self->state.rect_color, self->rdp_layer->colormap.colors); self->rdp_layer->mod->server_set_fgcolor(self->rdp_layer->mod, fgcolor); self->rdp_layer->mod->server_fill_rect(self->rdp_layer->mod, self->state.rect_x, self->state.rect_y, self->state.rect_cx, self->state.rect_cy); if (self->rdp_layer->rec_mode) { rdp_rec_check_file(self->rdp_layer); make_stream(rec_s); init_stream(rec_s, 512); s_push_layer(rec_s, iso_hdr, 4); out_uint8(rec_s, 1); out_uint16_le(rec_s, self->state.rect_x); out_uint16_le(rec_s, self->state.rect_y); out_uint16_le(rec_s, self->state.rect_cx); out_uint16_le(rec_s, self->state.rect_cy); out_uint32_le(rec_s, self->state.rect_color); rdp_rec_write_item(self->rdp_layer, rec_s); free_stream(rec_s); } } /*****************************************************************************/ /* Process a desktop save order */ static void APP_CC rdp_orders_process_desksave(struct rdp_orders *self, struct stream *s, int present, int delta) { //int width = 0; //int height = 0; if (present & 0x01) { in_uint32_le(s, self->state.desksave_offset); } if (present & 0x02) { rdp_orders_in_coord(s, &self->state.desksave_left, delta); } if (present & 0x04) { rdp_orders_in_coord(s, &self->state.desksave_top, delta); } if (present & 0x08) { rdp_orders_in_coord(s, &self->state.desksave_right, delta); } if (present & 0x10) { rdp_orders_in_coord(s, &self->state.desksave_bottom, delta); } if (present & 0x20) { in_uint8(s, self->state.desksave_action); } // width = (self->state.desksave_right - self->state.desksave_left) + 1; // height = (self->state.desksave_bottom - self->state.desksave_top) + 1; if (self->state.desksave_action == 0) { // ui_desktop_save(os->offset, os->left, os->top, width, height); } else { // ui_desktop_restore(os->offset, os->left, os->top, width, height); } } /*****************************************************************************/ /* Process a memory blt order */ static void APP_CC rdp_orders_process_memblt(struct rdp_orders *self, struct stream *s, int present, int delta) { struct rdp_bitmap *bitmap = (struct rdp_bitmap *)NULL; struct stream *rec_s = (struct stream *)NULL; char *bmpdata = (char *)NULL; if (present & 0x0001) { in_uint8(s, self->state.memblt_cache_id); in_uint8(s, self->state.memblt_color_table); } if (present & 0x0002) { rdp_orders_in_coord(s, &self->state.memblt_x, delta); } if (present & 0x0004) { rdp_orders_in_coord(s, &self->state.memblt_y, delta); } if (present & 0x0008) { rdp_orders_in_coord(s, &self->state.memblt_cx, delta); } if (present & 0x0010) { rdp_orders_in_coord(s, &self->state.memblt_cy, delta); } if (present & 0x0020) { in_uint8(s, self->state.memblt_opcode); } if (present & 0x0040) { rdp_orders_in_coord(s, &self->state.memblt_srcx, delta); } if (present & 0x0080) { rdp_orders_in_coord(s, &self->state.memblt_srcy, delta); } if (present & 0x0100) { in_uint16_le(s, self->state.memblt_cache_idx); } bitmap = self->cache_bitmap[self->state.memblt_cache_id] [self->state.memblt_cache_idx]; if (bitmap != 0) { self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, self->state.memblt_opcode); bmpdata = rdp_orders_convert_bitmap(self->rdp_layer->mod->rdp_bpp, self->rdp_layer->mod->xrdp_bpp, bitmap->data, bitmap->width, bitmap->height, self->cache_colormap [self->state.memblt_color_table]->colors); self->rdp_layer->mod->server_paint_rect(self->rdp_layer->mod, self->state.memblt_x, self->state.memblt_y, self->state.memblt_cx, self->state.memblt_cy, bmpdata, bitmap->width, bitmap->height, self->state.memblt_srcx, self->state.memblt_srcy); self->rdp_layer->mod->server_set_opcode(self->rdp_layer->mod, 0xcc); if (self->rdp_layer->rec_mode) { rdp_rec_check_file(self->rdp_layer); make_stream(rec_s); init_stream(rec_s, 512); s_push_layer(rec_s, iso_hdr, 4); out_uint8(rec_s, 2); out_uint8(rec_s, self->state.memblt_opcode); out_uint16_le(rec_s, self->state.memblt_x); out_uint16_le(rec_s, self->state.memblt_y); out_uint16_le(rec_s, self->state.memblt_cx); out_uint16_le(rec_s, self->state.memblt_cy); out_uint16_le(rec_s, self->state.memblt_cache_id); out_uint16_le(rec_s, self->state.memblt_cache_idx); out_uint16_le(rec_s, self->state.memblt_srcx); out_uint16_le(rec_s, self->state.memblt_srcy); rdp_rec_write_item(self->rdp_layer, rec_s); free_stream(rec_s); } if (bmpdata != bitmap->data) { g_free(bmpdata); } } } /*****************************************************************************/ /* Process a 3-way blt order */ static void APP_CC rdp_orders_process_triblt(struct rdp_orders *self, struct stream *s, int present, int delta) { /* not used */ } /*****************************************************************************/ /* Process a polyline order */ static void APP_CC rdp_orders_process_polyline(struct rdp_orders *self, struct stream *s, int present, int delta) { if (present & 0x01) { rdp_orders_in_coord(s, &self->state.polyline_x, delta); } if (present & 0x02) { rdp_orders_in_coord(s, &self->state.polyline_y, delta); } if (present & 0x04) { in_uint8(s, self->state.polyline_opcode); } if (present & 0x10) { rdp_orders_in_color(s, &self->state.polyline_fgcolor); } if (present & 0x20) { in_uint8(s, self->state.polyline_lines); } if (present & 0x40) { in_uint8(s, self->state.polyline_datasize); in_uint8a(s, self->state.polyline_data, self->state.polyline_datasize); } /* todo */ } /*****************************************************************************/ int APP_CC rdp_orders_process_orders(struct rdp_orders *self, struct stream *s, int num_orders) { int processed = 0; int order_flags = 0; int size = 0; int present = 0; int delta = 0; processed = 0; while (processed < num_orders) { in_uint8(s, order_flags); if (!(order_flags & RDP_ORDER_STANDARD)) { /* error, this should always be set */ break; } if (order_flags & RDP_ORDER_SECONDARY) { rdp_orders_process_secondary_order(self, s); } else { if (order_flags & RDP_ORDER_CHANGE) { in_uint8(s, self->state.order_type); } switch (self->state.order_type) { case RDP_ORDER_TRIBLT: case RDP_ORDER_TEXT2: size = 3; break; case RDP_ORDER_PATBLT: case RDP_ORDER_MEMBLT: case RDP_ORDER_LINE: size = 2; break; default: size = 1; break; } rdp_orders_in_present(s, &present, order_flags, size); if (order_flags & RDP_ORDER_BOUNDS) { if (!(order_flags & RDP_ORDER_LASTBOUNDS)) { rdp_orders_parse_bounds(self, s); } self->rdp_layer->mod->server_set_clip(self->rdp_layer->mod, self->state.clip_left, self->state.clip_top, (self->state.clip_right - self->state.clip_left) + 1, (self->state.clip_bottom - self->state.clip_top) + 1); } delta = order_flags & RDP_ORDER_DELTA; switch (self->state.order_type) { case RDP_ORDER_TEXT2: rdp_orders_process_text2(self, s, present, delta); break; case RDP_ORDER_DESTBLT: rdp_orders_process_destblt(self, s, present, delta); break; case RDP_ORDER_PATBLT: rdp_orders_process_patblt(self, s, present, delta); break; case RDP_ORDER_SCREENBLT: rdp_orders_process_screenblt(self, s, present, delta); break; case RDP_ORDER_LINE: rdp_orders_process_line(self, s, present, delta); break; case RDP_ORDER_RECT: rdp_orders_process_rect(self, s, present, delta); break; case RDP_ORDER_DESKSAVE: rdp_orders_process_desksave(self, s, present, delta); break; case RDP_ORDER_MEMBLT: rdp_orders_process_memblt(self, s, present, delta); break; case RDP_ORDER_TRIBLT: rdp_orders_process_triblt(self, s, present, delta); break; case RDP_ORDER_POLYLINE: rdp_orders_process_polyline(self, s, present, delta); break; default: /* error unknown order */ break; } if (order_flags & RDP_ORDER_BOUNDS) { self->rdp_layer->mod->server_reset_clip(self->rdp_layer->mod); } } processed++; } return 0; } /*****************************************************************************/ /* returns pointer, it might return bmpdata if the data doesn't need to be converted, else it mallocs it. The calling function must free it if needed */ char *APP_CC rdp_orders_convert_bitmap(int in_bpp, int out_bpp, char *bmpdata, int width, int height, int *palette) { char *out = (char *)NULL; char *src = (char *)NULL; char *dst = (char *)NULL; int i = 0; int j = 0; int red = 0; int green = 0; int blue = 0; int pixel = 0; if ((in_bpp == 8) && (out_bpp == 8)) { out = (char *)g_malloc(width * height, 0); src = bmpdata; dst = out; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { pixel = *((tui8 *)src); pixel = palette[pixel]; SPLITCOLOR32(red, green, blue, pixel); pixel = COLOR8(red, green, blue); *dst = pixel; src++; dst++; } } return out; } if ((in_bpp == 8) && (out_bpp == 16)) { out = (char *)g_malloc(width * height * 2, 0); src = bmpdata; dst = out; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { pixel = *((tui8 *)src); pixel = palette[pixel]; SPLITCOLOR32(red, green, blue, pixel); pixel = COLOR16(red, green, blue); *((tui16 *)dst) = pixel; src++; dst += 2; } } return out; } if ((in_bpp == 8) && (out_bpp == 24)) { out = (char *)g_malloc(width * height * 4, 0); src = bmpdata; dst = out; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { pixel = *((tui8 *)src); pixel = palette[pixel]; SPLITCOLOR32(red, green, blue, pixel); pixel = COLOR24RGB(red, green, blue); *((tui32 *)dst) = pixel; src++; dst += 4; } } return out; } if ((in_bpp == 15) && (out_bpp == 16)) { out = (char *)g_malloc(width * height * 2, 0); src = bmpdata; dst = out; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { pixel = *((tui16 *)src); SPLITCOLOR15(red, green, blue, pixel); pixel = COLOR16(red, green, blue); *((tui16 *)dst) = pixel; src += 2; dst += 2; } } return out; } if ((in_bpp == 15) && (out_bpp == 24)) { out = (char *)g_malloc(width * height * 4, 0); src = bmpdata; dst = out; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { pixel = *((tui16 *)src); SPLITCOLOR15(red, green, blue, pixel); pixel = COLOR24RGB(red, green, blue); *((tui32 *)dst) = pixel; src += 2; dst += 4; } } return out; } if ((in_bpp == 16) && (out_bpp == 16)) { return bmpdata; } if ((in_bpp == 16) && (out_bpp == 24)) { out = (char *)g_malloc(width * height * 4, 0); src = bmpdata; dst = out; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { pixel = *((tui16 *)src); SPLITCOLOR16(red, green, blue, pixel); pixel = COLOR24RGB(red, green, blue); *((tui32 *)dst) = pixel; src += 2; dst += 4; } } return out; } if ((in_bpp == 24) && (out_bpp == 24)) { out = (char *)g_malloc(width * height * 4, 0); src = bmpdata; dst = out; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { blue = *((tui8 *)src); src++; green = *((tui8 *)src); src++; red = *((tui8 *)src); src++; pixel = COLOR24RGB(red, green, blue); *((tui32 *)dst) = pixel; dst += 4; } } return out; } return 0; } /*****************************************************************************/ /* returns color or 0 */ int APP_CC rdp_orders_convert_color(int in_bpp, int out_bpp, int in_color, int *palette) { int pixel = 0; int red = 0; int green = 0; int blue = 0; if ((in_bpp == 8) && (out_bpp == 8)) { pixel = palette[in_color]; SPLITCOLOR32(red, green, blue, pixel); pixel = COLOR8(red, green, blue); return pixel; } if ((in_bpp == 8) && (out_bpp == 16)) { pixel = palette[in_color]; SPLITCOLOR32(red, green, blue, pixel); pixel = COLOR16(red, green, blue); return pixel; } if ((in_bpp == 8) && (out_bpp == 24)) { pixel = palette[in_color]; SPLITCOLOR32(red, green, blue, pixel); pixel = COLOR24BGR(red, green, blue); return pixel; } if ((in_bpp == 15) && (out_bpp == 16)) { pixel = in_color; SPLITCOLOR15(red, green, blue, pixel); pixel = COLOR16(red, green, blue); return pixel; } if ((in_bpp == 15) && (out_bpp == 24)) { pixel = in_color; SPLITCOLOR15(red, green, blue, pixel); pixel = COLOR24BGR(red, green, blue); return pixel; } if ((in_bpp == 16) && (out_bpp == 16)) { return in_color; } if ((in_bpp == 16) && (out_bpp == 24)) { pixel = in_color; SPLITCOLOR16(red, green, blue, pixel); pixel = COLOR24BGR(red, green, blue); return pixel; } if ((in_bpp == 24) && (out_bpp == 24)) { return in_color; } return 0; }