size_t str(char * buffer, size_t sz, const RDPOrderCommon & common) const { size_t lg = common.str(buffer, sz, true); lg += snprintf( buffer+lg, sz-lg, "lineto(back_mode=%.2x " "startx=%d starty=%d endx=%d endy=%d " "rop2=%d back_color=%.6x" "pen.style=%d pen.width=%d pen.color=%.6x " "\n", unsigned(this->back_mode), this->startx, this->starty, this->endx, this->endy, this->rop2, this->back_color.as_bgr().to_u32(), this->pen.style, this->pen.width, this->pen.color.as_bgr().to_u32() ); if (lg >= sz){ return sz; } return lg; }
size_t str(char * buffer, size_t sz, const RDPOrderCommon & common) const { size_t lg = 0; lg += common.str(buffer + lg, sz - lg, true); lg += snprintf(buffer + lg, sz - lg, "polygoncb(xStart=%d yStart=%d bRop2=0x%02X fillMode=%d " "backColor=%.6x foreColor=%.6x " "brush.org_x=%d brush.org_y=%d " "brush.style=%d brush.hatch=%d " "NumDeltaEntries=%d DeltaEntries=(", this->xStart, this->yStart, unsigned(this->bRop2), this->fillMode, this->backColor.as_bgr().to_u32(), this->foreColor.as_bgr().to_u32(), this->brush.org_x, this->brush.org_y, this->brush.style, this->brush.hatch, this->NumDeltaEntries); for (uint8_t i = 0; i < this->NumDeltaEntries; i++) { if (i) { lg += snprintf(buffer + lg, sz - lg, " "); } lg += snprintf(buffer + lg, sz - lg, "(%d, %d)", this->deltaPoints[i].xDelta, this->deltaPoints[i].yDelta); } lg += snprintf(buffer + lg, sz - lg, "))"); if (lg >= sz) { return sz; } return lg; }
void emit(Stream & stream, RDPOrderCommon & common, const RDPOrderCommon & oldcommon, const RDPScrBlt & oldcmd) const { using namespace RDP; RDPPrimaryOrderHeader header(STANDARD, 0); if (!common.clip.contains(this->rect)){ header.control |= BOUNDS; } // SCREENBLT fields bytes (1 byte) // ------------------------------ // 0x01: x coordinate // 0x02: y coordinate // 0x04: cx coordinate // 0x08: cy coordinate // 0x10: rop byte // 0x20: srcx coordinate // 0x40: srcy coordinate DeltaRect dr(this->rect, oldcmd.rect); // RDP specs says that we can have DELTA only if we // have bounds. Can't see the rationale and rdesktop don't do it // by the book. Behavior should be checked with server and clients // from Microsoft. Looks like an error in RDP specs. header.control |= ((dr.fully_relative() && is_1_byte(this->srcx - oldcmd.srcx) && is_1_byte(this->srcy - oldcmd.srcy)) * DELTA); header.fields = (dr.dleft != 0 ) * 0x01 | (dr.dtop != 0 ) * 0x02 | (dr.dwidth != 0 ) * 0x04 | (dr.dheight != 0 ) * 0x08 | (this->rop != oldcmd.rop ) * 0x10 | ((this->srcx - oldcmd.srcx) != 0 ) * 0x20 | ((this->srcy - oldcmd.srcy) != 0 ) * 0x40 ; common.emit(stream, header, oldcommon); header.emit_rect(stream, 0x01, this->rect, oldcmd.rect); if (header.fields & 0x10){ stream.out_uint8(this->rop); } header.emit_src(stream, 0x20, this->srcx, this->srcy, oldcmd.srcx, oldcmd.srcy); }
void emit( Stream & stream, RDPOrderCommon & common, const RDPOrderCommon & oldcommon , const RDPMultiOpaqueRect & oldcmd) const { RDPPrimaryOrderHeader header(RDP::STANDARD, 0); int16_t nLeftRect = 0; int16_t nTopRect = 0; int16_t nWidth = 0; int16_t nHeight = 0; if (!common.clip.contains(Rect(nLeftRect, nTopRect, nWidth, nHeight))) { header.control |= RDP::BOUNDS; } else { for (uint8_t i = 0; i < this->nDeltaEntries; i++) { nLeftRect += this->deltaEncodedRectangles[i].leftDelta; nTopRect += this->deltaEncodedRectangles[i].topDelta; nWidth = this->deltaEncodedRectangles[i].width; nHeight = this->deltaEncodedRectangles[i].height; if (!common.clip.contains(Rect(nLeftRect, nTopRect, nWidth, nHeight))) { header.control |= RDP::BOUNDS; break; } } } header.control |= (is_1_byte(this->nLeftRect - oldcmd.nLeftRect) && is_1_byte(this->nTopRect - oldcmd.nTopRect) && is_1_byte(this->nWidth - oldcmd.nWidth) && is_1_byte(this->nHeight - oldcmd.nHeight)) * RDP::DELTA; header.fields = (this->nLeftRect != oldcmd.nLeftRect ) * 0x0001 | (this->nTopRect != oldcmd.nTopRect ) * 0x0002 | (this->nWidth != oldcmd.nWidth ) * 0x0004 | (this->nHeight != oldcmd.nHeight ) * 0x0008 | ((this->_Color & 0x0000FF) != (oldcmd._Color & 0x0000FF)) * 0x0010 | ((this->_Color & 0x00FF00) != (oldcmd._Color & 0x00FF00)) * 0x0020 | ((this->_Color & 0xFF0000) != (oldcmd._Color & 0xFF0000)) * 0x0040 | (this->nDeltaEntries != oldcmd.nDeltaEntries ) * 0x0080 | ( (this->nDeltaEntries != oldcmd.nDeltaEntries) || memcmp(this->deltaEncodedRectangles, oldcmd.deltaEncodedRectangles, this->nDeltaEntries * sizeof(RDP::DeltaEncodedRectangle)) ) * 0x0100 ; common.emit(stream, header, oldcommon); header.emit_coord(stream, 0x0001, this->nLeftRect, oldcmd.nLeftRect); header.emit_coord(stream, 0x0002, this->nTopRect, oldcmd.nTopRect); header.emit_coord(stream, 0x0004, this->nWidth, oldcmd.nWidth); header.emit_coord(stream, 0x0008, this->nHeight, oldcmd.nHeight); if (header.fields & 0x0010) { stream.out_uint8(this->_Color); } if (header.fields & 0x0020) { stream.out_uint8(this->_Color >> 8); }
size_t str(char * buffer, size_t sz, const RDPOrderCommon & common) const { size_t lg = 0; lg += common.str(buffer + lg, sz - lg, true); lg += snprintf(buffer + lg, sz - lg, "ellipseSC(leftRect=%d topRect=%d rightRect=%d bottomRect=%d bRop2=0x%02X " "fillMode=%d Color=%.6x)", this->el.left(), this->el.top(), this->el.right(), this->el.bottom(), unsigned(this->bRop2), this->fillMode, this->color.as_bgr().to_u32()); if (lg >= sz) { return sz; } return lg; }
size_t str(char * buffer, size_t sz, const RDPOrderCommon & common) const { size_t lg = common.str(buffer, sz); lg += snprintf( buffer+lg, sz-lg, "scrblt(rect(%d,%d,%d,%d) rop=%x srcx=%d srcy=%d)\n", this->rect.x, this->rect.y, this->rect.cx, this->rect.cy, this->rop, this->srcx, this->srcy); if (lg >= sz){ return sz; } return lg; }
size_t str(char * buffer, size_t sz, const RDPOrderCommon & common) const { size_t lg = common.str(buffer, sz, !common.clip.contains(this->rect)); lg += snprintf( buffer+lg, sz-lg, "destblt(rect(%d,%d,%d,%d) rop=%x)\n", this->rect.x, this->rect.y, this->rect.cx, this->rect.cy, this->rop); if (lg >= sz){ return sz; } return lg; }
void emit(OutStream & stream, RDPOrderCommon & common, const RDPOrderCommon & oldcommon, const RDPLineTo & oldcmd) const { using namespace RDP; RDPPrimaryOrderHeader header(STANDARD, 0); // TODO check that if (!(common.clip.contains_pt(this->startx, this->starty) && common.clip.contains_pt(this->endx, this->endy))){ header.control |= BOUNDS; } header.control |= (is_1_byte(this->startx - oldcmd.startx) && is_1_byte(this->starty - oldcmd.starty) && is_1_byte(this->endx - oldcmd.endx) && is_1_byte(this->endy - oldcmd.endy)) * DELTA; header.fields = (this->back_mode != oldcmd.back_mode ) * 0x001 | (this->startx != oldcmd.startx ) * 0x002 | (this->starty != oldcmd.starty ) * 0x004 | (this->endx != oldcmd.endx ) * 0x008 | (this->endy != oldcmd.endy ) * 0x010 | (this->back_color != oldcmd.back_color ) * 0x020 | (this->rop2 != oldcmd.rop2 ) * 0x040 | (this->pen.style != oldcmd.pen.style ) * 0x080 | (this->pen.width != oldcmd.pen.width ) * 0x100 | (this->pen.color != oldcmd.pen.color ) * 0x200 ; common.emit(stream, header, oldcommon); if (header.fields & 0x001) { stream.out_uint16_le(this->back_mode); } header.emit_coord(stream, 0x02, this->startx, oldcmd.startx); header.emit_coord(stream, 0x04, this->starty, oldcmd.starty); header.emit_coord(stream, 0x08, this->endx, oldcmd.endx); header.emit_coord(stream, 0x10, this->endy, oldcmd.endy); if (header.fields & 0x20) { emit_rdp_color(stream, this->back_color); } if (header.fields & 0x40) { stream.out_uint8(this->rop2); } header.emit_pen(stream, 0x80, this->pen, oldcmd.pen); }
void emit(OutStream & stream, RDPOrderCommon & common, const RDPOrderCommon & oldcommon, const RDPEllipseSC & oldcmd) const { RDPPrimaryOrderHeader header(RDP::STANDARD, 0); if (!common.clip.contains(this->el.get_rect())){ header.control |= RDP::BOUNDS; } const int16_t oldleft = oldcmd.el.left(); const int16_t oldtop = oldcmd.el.top(); const int16_t oldright = oldcmd.el.right(); const int16_t oldbottom = oldcmd.el.bottom(); header.control |= (is_1_byte(this->el.left() - oldleft) && is_1_byte(this->el.top() - oldtop) && is_1_byte(this->el.right() - oldright) && is_1_byte(this->el.bottom() - oldbottom)) * RDP::DELTA; header.fields = ( this->el.left() != oldleft ) * 0x0001 |(this->el.top() != oldtop ) * 0x0002 |(this->el.right() != oldright ) * 0x0004 |(this->el.bottom() != oldbottom ) * 0x0008 |(this->bRop2 != oldcmd.bRop2 ) * 0x0010 |(this->fillMode != oldcmd.fillMode) * 0x0020 |(this->color != oldcmd.color ) * 0x0040; common.emit(stream, header, oldcommon); header.emit_coord(stream, 0x0001, this->el.left(), oldleft); header.emit_coord(stream, 0x0002, this->el.top(), oldtop); header.emit_coord(stream, 0x0004, this->el.right(), oldright); header.emit_coord(stream, 0x0008, this->el.bottom(), oldbottom); if (header.fields & 0x0010) { stream.out_uint8(this->bRop2); } if (header.fields & 0x0020) { stream.out_uint8(this->fillMode); } if (header.fields & 0x0040) { emit_rdp_color(stream, this->color); } // LOG(LOG_INFO, "RDPEllipseSC::emit: header fields=0x%02X", header.fields); // LOG(LOG_INFO, "RDPEllipseSC::emit: header color=0x%02X", this->color); }
size_t str(char * buffer, size_t sz, const RDPOrderCommon & common) const { size_t lg = 0; lg += common.str(buffer + lg, sz - lg, true); lg += snprintf(buffer + lg, sz - lg, "MultiDstBlt(nLeftRect=%d nTopRect=%d nWidth=%d nHeight=%d bRop=0x%02X nDeltaEntries=%d " "CodedDeltaList=(", this->nLeftRect, this->nTopRect, this->nWidth, this->nHeight, this->bRop, this->nDeltaEntries); for (uint8_t i = 0; i < this->nDeltaEntries; i++) { if (i) { lg += snprintf(buffer + lg, sz - lg, " "); } lg += snprintf(buffer + lg, sz - lg, "(%d, %d, %d, %d)", this->deltaEncodedRectangles[i].leftDelta, this->deltaEncodedRectangles[i].topDelta, this->deltaEncodedRectangles[i].width, this->deltaEncodedRectangles[i].height); } lg += snprintf(buffer + lg, sz - lg, "))"); if (lg >= sz) { return sz; } return lg; }
void emit(OutStream & stream, RDPOrderCommon & common, const RDPOrderCommon & oldcommon, const RDPPolygonCB & oldcmd) const { RDPPrimaryOrderHeader header(RDP::STANDARD, 0); // TODO check that int16_t pointx = this->xStart; int16_t pointy = this->yStart; if (!common.clip.contains_pt(pointx, pointy)) { header.control |= RDP::BOUNDS; } else { for (uint8_t i = 0; i < this->NumDeltaEntries; i++) { pointx += this->deltaPoints[i].xDelta; pointy += this->deltaPoints[i].yDelta; if (!common.clip.contains_pt(pointx, pointy)) { header.control |= RDP::BOUNDS; break; } } } header.control |= (is_1_byte(this->xStart - oldcmd.xStart) && is_1_byte(this->yStart - oldcmd.yStart)) * RDP::DELTA; header.fields = (this->xStart != oldcmd.xStart ) * 0x0001 | (this->yStart != oldcmd.yStart ) * 0x0002 | (this->bRop2 != oldcmd.bRop2 ) * 0x0004 | (this->fillMode != oldcmd.fillMode ) * 0x0008 | (this->backColor != oldcmd.backColor ) * 0x0010 | (this->foreColor != oldcmd.foreColor ) * 0x0020 | (this->brush.org_x != oldcmd.brush.org_x ) * 0x0040 | (this->brush.org_y != oldcmd.brush.org_y ) * 0x0080 | (this->brush.style != oldcmd.brush.style ) * 0x0100 | (this->brush.hatch != oldcmd.brush.hatch ) * 0x0200 | (memcmp(this->brush.extra, oldcmd.brush.extra, 7) != 0) * 0x0400 | (this->NumDeltaEntries != oldcmd.NumDeltaEntries) * 0x0800 | ((this->NumDeltaEntries != oldcmd.NumDeltaEntries) || memcmp(this->deltaPoints, oldcmd.deltaPoints, this->NumDeltaEntries * sizeof(DeltaPoint)) ) * 0x1000 ; common.emit(stream, header, oldcommon); header.emit_coord(stream, 0x0001, this->xStart, oldcmd.xStart); header.emit_coord(stream, 0x0002, this->yStart, oldcmd.yStart); if (header.fields & 0x0004) { stream.out_uint8(this->bRop2); } if (header.fields & 0x0008) { stream.out_uint8(this->fillMode); } if (header.fields & 0x0010) { emit_rdp_color(stream, this->backColor); } if (header.fields & 0x0020) { emit_rdp_color(stream, this->foreColor); } header.emit_brush(stream, 0x0040, this->brush, oldcmd.brush); if (header.fields & 0x0800) { stream.out_uint8(this->NumDeltaEntries); } if (header.fields & 0x1000) { uint32_t offset_cbData = stream.get_offset(); stream.out_clear_bytes(1); uint8_t * zeroBit = stream.get_current(); stream.out_clear_bytes((this->NumDeltaEntries + 3) / 4); *zeroBit = 0; for (uint8_t i = 0, m4 = 0; i < this->NumDeltaEntries; i++, m4++) { if (m4 == 4) { m4 = 0; } if (i && !m4) { *(++zeroBit) = 0; } if (!this->deltaPoints[i].xDelta) { *zeroBit |= (1 << (7 - m4 * 2)); } else { stream.out_DEP(this->deltaPoints[i].xDelta); } if (!this->deltaPoints[i].yDelta) { *zeroBit |= (1 << (6 - m4 * 2)); } else { stream.out_DEP(this->deltaPoints[i].yDelta); } } stream.set_out_uint8(stream.get_offset() - offset_cbData - 1, offset_cbData); } }
void emit( OutStream & stream, RDPOrderCommon & common, const RDPOrderCommon & oldcommon , const RDPMultiDstBlt & oldcmd) const { RDPPrimaryOrderHeader header(RDP::STANDARD, 0); int16_t nLeftRect = 0; int16_t nTopRect = 0; int16_t nWidth = 0; int16_t nHeight = 0; if (!common.clip.contains(Rect(nLeftRect, nTopRect, nWidth, nHeight))) { header.control |= RDP::BOUNDS; } else { for (uint8_t i = 0; i < this->nDeltaEntries; i++) { nLeftRect += this->deltaEncodedRectangles[i].leftDelta; nTopRect += this->deltaEncodedRectangles[i].topDelta; nWidth = this->deltaEncodedRectangles[i].width; nHeight = this->deltaEncodedRectangles[i].height; if (!common.clip.contains(Rect(nLeftRect, nTopRect, nWidth, nHeight))) { header.control |= RDP::BOUNDS; break; } } } header.control |= (is_1_byte(this->nLeftRect - oldcmd.nLeftRect) && is_1_byte(this->nTopRect - oldcmd.nTopRect) && is_1_byte(this->nWidth - oldcmd.nWidth) && is_1_byte(this->nHeight - oldcmd.nHeight)) * RDP::DELTA; header.fields = (this->nLeftRect != oldcmd.nLeftRect ) * 0x0001 | (this->nTopRect != oldcmd.nTopRect ) * 0x0002 | (this->nWidth != oldcmd.nWidth ) * 0x0004 | (this->nHeight != oldcmd.nHeight ) * 0x0008 | (this->bRop != oldcmd.bRop ) * 0x0010 | (this->nDeltaEntries != oldcmd.nDeltaEntries) * 0x0020 | ( (this->nDeltaEntries != oldcmd.nDeltaEntries) || memcmp(this->deltaEncodedRectangles, oldcmd.deltaEncodedRectangles, this->nDeltaEntries * sizeof(RDP::DeltaEncodedRectangle)) ) * 0x0040 ; common.emit(stream, header, oldcommon); header.emit_coord(stream, 0x0001, this->nLeftRect, oldcmd.nLeftRect); header.emit_coord(stream, 0x0002, this->nTopRect, oldcmd.nTopRect); header.emit_coord(stream, 0x0004, this->nWidth, oldcmd.nWidth); header.emit_coord(stream, 0x0008, this->nHeight, oldcmd.nHeight); if (header.fields & 0x0010) { stream.out_uint8(this->bRop); } if (header.fields & 0x0020) { stream.out_uint8(this->nDeltaEntries); } if (header.fields & 0x0040) { uint32_t offset_cbData = stream.get_offset(); stream.out_clear_bytes(2); uint8_t * zeroBit = stream.get_current(); stream.out_clear_bytes((this->nDeltaEntries + 1) / 2); *zeroBit = 0; for (uint8_t i = 0, m2 = 0; i < this->nDeltaEntries; i++, m2++) { if (m2 == 2) { m2 = 0; } if (i && !m2) { *(++zeroBit) = 0; } if (!this->deltaEncodedRectangles[i].leftDelta) { *zeroBit |= (1 << (7 - m2 * 4)); } else { stream.out_DEP(this->deltaEncodedRectangles[i].leftDelta); } if (!this->deltaEncodedRectangles[i].topDelta) { *zeroBit |= (1 << (6 - m2 * 4)); } else { stream.out_DEP(this->deltaEncodedRectangles[i].topDelta); } if (!this->deltaEncodedRectangles[i].width) { *zeroBit |= (1 << (5 - m2 * 4)); } else { stream.out_DEP(this->deltaEncodedRectangles[i].width); } if (!this->deltaEncodedRectangles[i].height) { *zeroBit |= (1 << (4 - m2 * 4)); } else { stream.out_DEP(this->deltaEncodedRectangles[i].height); } } stream.set_out_uint16_le(stream.get_offset() - offset_cbData - 2, offset_cbData); } } // void emit(OutStream & stream, RDPOrderCommon & common, const RDPOrderCommon & oldcommon, const RDPMultiDstBlt & oldcmd) const
// order to stream returns true if state clip must be changed // it does not change state by itself void emit(OutStream & stream, RDPOrderCommon & common, const RDPOrderCommon & oldcommon, const RDPOpaqueRect & oldcmd) const { using namespace RDP; RDPPrimaryOrderHeader header(STANDARD, 0); if (!common.clip.contains(this->rect)){ header.control |= BOUNDS; } // OPAQUERECT fields bytes (1 byte) // ------------------------------ // 0x01: x coordinate // 0x02: y coordinate // 0x04: cx coordinate // 0x08: cy coordinate // 0x10: red color byte // 0x20: green color byte // 0x40: blue color byte // Note by CGR: // ------------ // As far as we can see the OPAQUERECT fields called "red" "green" and // "blue" don't care much for actual color components. Really they // should be called "first color byte", "second color byte" and "third // color byte". They are red green and blue only in 24 bits. In 15 or 16 // one byte is always empty and changing green component will // change both used bytes. DeltaRect dr(this->rect, oldcmd.rect); // RDP specs says that we can have DELTA only if we // have bounds. Can't see the rationale and rdesktop don't do it // by the book. Behavior should be checked with server and clients // from Microsoft. Looks like an error in RDP specs. header.control |= dr.fully_relative() * DELTA; uint32_t diff_color = this->color ^ oldcmd.color; // LOG(LOG_INFO, "emit opaque rect old_color = %.6x new_color = %.6x\n", oldcmd.color, this->color); header.fields = (dr.dleft != 0) * 0x01 | (dr.dtop != 0) * 0x02 | (dr.dwidth != 0) * 0x04 | (dr.dheight != 0) * 0x08 | ((diff_color & 0x0000FF) != 0) * 0x10 | ((diff_color & 0x00FF00) != 0) * 0x20 | ((diff_color & 0xFF0000) != 0) * 0x40 ; common.emit(stream, header, oldcommon); header.emit_rect(stream, 0x01, this->rect, oldcmd.rect); if (header.fields & 0x10){ stream.out_uint8(this->color); } if (header.fields & 0x20){ stream.out_uint8(this->color >> 8); }