diff --git a/libfreerdp-core/fastpath.c b/libfreerdp-core/fastpath.c index b5bf10653..1778f2189 100644 --- a/libfreerdp-core/fastpath.c +++ b/libfreerdp-core/fastpath.c @@ -203,6 +203,12 @@ static void fastpath_recv_update_data(rdpFastPath* fastpath, STREAM* s) uint8 compression; uint8 compressionFlags; STREAM* update_stream; + rdpRdp *rdp; + uint32 roff; + uint32 rlen; + uint32 i; + + rdp = fastpath->rdp; fastpath_read_update_header(s, &updateCode, &fragmentation, &compression); @@ -216,9 +222,21 @@ static void fastpath_recv_update_data(rdpFastPath* fastpath, STREAM* s) if (compressionFlags != 0) { - printf("FastPath compression is not yet implemented!\n"); - stream_seek(s, size); - return; + if (decompress_rdp(rdp, s->data, size, + compressionFlags, &roff, &rlen)) + { + /* need more space to insert decompressed data */ + i = rlen - size; + stream_extend(s, i); + + /* copy decompressed data */ + memcpy(s->p, &rdp->mppc->history_buf[roff], rlen); + } + else + { + printf("decompress_rdp() failed\n"); + stream_seek(s, size); + } } update_stream = NULL; diff --git a/libfreerdp-core/info.c b/libfreerdp-core/info.c index f03981e17..37f30e103 100644 --- a/libfreerdp-core/info.c +++ b/libfreerdp-core/info.c @@ -495,7 +495,7 @@ void rdp_write_info_packet(STREAM* s, rdpSettings* settings) flags |= INFO_REMOTECONSOLEAUDIO; if (settings->compression) - flags |= INFO_COMPRESSION | PACKET_COMPR_TYPE_64K; + flags |= INFO_COMPRESSION | INFO_PACKET_COMPR_TYPE_64K; domain = (uint8*)freerdp_uniconv_out(settings->uniconv, settings->domain, &length); cbDomain = length; diff --git a/libfreerdp-core/mppc.c b/libfreerdp-core/mppc.c index ab02f8e49..d934a0156 100644 --- a/libfreerdp-core/mppc.c +++ b/libfreerdp-core/mppc.c @@ -24,10 +24,637 @@ #include #include "rdp.h" +int decompress_rdp(rdpRdp *rdp, + uint8 *cbuf, + int len, + int ctype, + uint32 *roff, + uint32 *rlen) +{ + int type = ctype & 0x0f; + + switch (type) + { + case PACKET_COMPR_TYPE_8K: + return decompress_rdp_4(rdp, cbuf, len, ctype, roff, rlen); + break; + + case PACKET_COMPR_TYPE_64K: + return decompress_rdp_5(rdp, cbuf, len, ctype, roff, rlen); + break; + + case PACKET_COMPR_TYPE_RDP6: + return decompress_rdp_6(rdp, cbuf, len, ctype, roff, rlen); + break; + + case PACKET_COMPR_TYPE_RDP61: + return decompress_rdp_61(rdp, cbuf, len, ctype, roff, rlen); + break; + + default: + printf("mppc.c: invalid RDP compression code\n"); + return False; + } +} + +/** + * decompress RDP 4 data + * + * @param rdp per session information + * @param cbuf compressed data + * @param len length of compressed data + * @param ctype compression flags + * @param roff starting offset of uncompressed data + * @param rlen length of uncompressed data + * + * @return True on success, False on failure + */ + +int decompress_rdp_4(rdpRdp *rdp, + uint8 *cbuf, + int len, + int ctype, + uint32 *roff, + uint32 *rlen) +{ + return False; +} + +/** + * decompress RDP 5 data + * + * @param rdp per session information + * @param cbuf compressed data + * @param len length of compressed data + * @param ctype compression flags + * @param roff starting offset of uncompressed data + * @param rlen length of uncompressed data + * + * @return True on success, False on failure + */ + +int decompress_rdp_5(rdpRdp *rdp, + uint8 *cbuf, + int len, + int ctype, + uint32 *roff, + uint32 *rlen) +{ + uint8 *history_buf; /* uncompressed data goes here */ + uint8 *history_ptr; /* points to next free slot in bistory_buf */ + uint32 d32; /* we process 4 compressed bytes at a time */ + uint16 copy_offset; /* location to copy data from */ + uint16 lom; /* length of match */ + uint8 *src_ptr; /* used while copying compressed data */ + uint8 *cptr; /* points to next byte in cbuf */ + uint8 cur_byte; /* last byte fetched from cbuf */ + int bits_left; /* bits left in d32 for processing */ + int cur_bits_left; /* bits left in cur_byte for processing */ + int tmp; + uint32 i32; + + if ((rdp->mppc == NULL) || (rdp->mppc->history_buf == NULL)) + { + return False; + } + + src_ptr = 0; + cptr = cbuf; + copy_offset = 0; + lom = 0; + bits_left = 0; + cur_bits_left = 0; + d32 = 0; + cur_byte = 0; + *rlen = 0; + + mprintf("decompress_rdp_5: *** ctype=0x%x len=%d ***\n", ctype, len); + + /* get start of history buffer */ + history_buf = rdp->mppc->history_buf; + + /* get next free slot in history buffer */ + history_ptr = rdp->mppc->history_ptr; + *roff = history_ptr - history_buf; + + if (ctype & PACKET_AT_FRONT) + { + /* place compressed data at start of history buffer */ + mprintf("decompress_rdp_5: got PACKET_AT_FRONT\n"); + history_ptr = rdp->mppc->history_buf; + *roff = 0; + } + + if (ctype & PACKET_FLUSHED) + { + /* re-init history buffer */ + mprintf("decompress_rdp_5: got PACKET_FLUSHED\n"); + history_ptr = rdp->mppc->history_buf; + memset(history_buf, 0, RDP5_HISTORY_BUF_SIZE); + *roff = 0; + } + + if ((ctype & PACKET_COMPRESSED) != PACKET_COMPRESSED) + { + /* data in cbuf is not compressed - copy to history buf as is */ + mprintf("decompress_rdp_5: got ! PACKET_COMPRESSED\n"); + memcpy(history_ptr, cbuf, len); + history_ptr += len; + *rlen = history_ptr - rdp->mppc->history_ptr; + rdp->mppc->history_ptr = history_ptr; + return True; + } + + /* load initial data */ + tmp = 24; + while (cptr < cbuf + len) + { + i32 = *cptr++; + d32 |= i32 << tmp; + bits_left += 8; + tmp -= 8; + if (tmp < 0) + { + break; + } + } + + if (cptr < cbuf + len) + { + cur_byte = *cptr++; + cur_bits_left = 8; + } + else + { + cur_bits_left = 0; + } + + /* + ** start uncompressing data in cbuf + */ + + while (bits_left >= 8) + { + /* + value 0xxxxxxx = literal, not encoded + value 10xxxxxx = literal, encoded + value 11111xxx = copy offset 0 - 63 + value 11110xxx = copy offset 64 - 319 + value 1110xxxx = copy offset 320 - 2367 + value 110xxxxx = copy offset 2368+ + */ + + /* + at this point, we are guaranteed that d32 has 32 bits to + be processed, unless we have reached end of cbuf + */ + + copy_offset = 0; + + if ((d32 & 0x80000000) == 0) + { + /* got a literal */ + mprintf("decompress_rdp_5: got literal\n"); + *history_ptr++ = d32 >> 24; + d32 <<= 8; + bits_left -= 8; + } + else if ((d32 & 0xc0000000) == 0x80000000) + { + /* got encoded literal */ + mprintf("decompress_rdp_5: got encoded literal\n"); + d32 <<= 2; + *history_ptr++ = (d32 >> 25) | 0x80; + d32 <<= 7; + bits_left -= 9; + } + else if ((d32 & 0xf8000000) == 0xf8000000) + { + /* got copy offset in range 0 - 63, */ + /* with 6 bit copy offset */ + mprintf("decompress_rdp_5: " + "got copy offset in range 0 - 63\n"); + d32 <<= 5; + copy_offset = d32 >> 26; + d32 <<= 6; + bits_left -= 11; + } + else if ((d32 & 0xf8000000) == 0xf0000000) + { + /* got copy offset in range 64 - 319, */ + /* with 8 bit copy offset */ + mprintf("decompress_rdp_5: " + "got copy offset in range 64 - 319\n"); + d32 <<= 5; + copy_offset = d32 >> 24; + copy_offset += 64; + d32 <<= 8; + bits_left -= 13; + } + else if ((d32 & 0xf0000000) == 0xe0000000) + { + /* got copy offset in range 320 - 2367, */ + /* with 11 bits copy offset */ + mprintf("decompress_rdp_5: " + "got copy offset in range 320 - 2367\n"); + d32 <<= 4; + copy_offset = d32 >> 21; + copy_offset += 320; + d32 <<= 11; + bits_left -= 15; + } + else if ((d32 & 0xe0000000) == 0xc0000000) + { + /* got copy offset in range 2368+, */ + /* with 16 bits copy offset */ + mprintf("decompress_rdp_5: " + "got copy offset in range 2368+\n"); + d32 <<= 3; + copy_offset = d32 >> 16; + copy_offset += 2368; + d32 <<= 16; + bits_left -= 19; + } + + /* + ** get more bits before we process length of match + */ + +#if 1 + /* how may bits do we need to get? */ + tmp = 32 - bits_left; + + while (tmp) + { + if (cur_bits_left < tmp) + { + /* we have less bits than we need */ + i32 = cur_byte >> (8 - cur_bits_left); + d32 |= i32 << ((32 - bits_left) - cur_bits_left); + bits_left += cur_bits_left; + tmp -= cur_bits_left; + if (cptr < cbuf + len) + { + /* more compressed data available */ + cur_byte = *cptr++; + cur_bits_left = 8; + } + else + { + /* no more compressed data available */ + tmp = 0; + cur_bits_left = 0; + } + } + else if (cur_bits_left > tmp) + { + /* we have more bits than we need */ + d32 |= cur_byte >> (8 - tmp); + cur_byte <<= tmp; + cur_bits_left -= tmp; + bits_left = 32; + break; + } + else + { + /* we have just the right amount of bits */ + d32 |= cur_byte >> (8 - tmp); + bits_left = 32; + if (cptr < cbuf + len) + { + cur_byte = *cptr++; + cur_bits_left = 8; + } + else + { + cur_bits_left = 0; + } + break; + } + } + #else + // optimization code under development + + // LK_TODO either use only i32 or make cur_byte uint32_t + // make cbuf + len a const variable so we dont compute it + // each time + + /* if there are no more bits to get, skip this */ + if (!cur_bits_left) + { + goto no_more_bits1; + } + + /* how may bits do we need to get? */ + tmp = 32 - bits_left; + + while (tmp) + { + if (tmp > 8) + { + i32 = cur_byte; + d32 |= i32 << (24 - bits_left); + bits_left += cur_bits_left; + tmp -= cur_bits_left; + if (cptr < cbuf + len) + { + cur_byte = *cptr++; + cur_bits_left = 8; + } + else + { + cur_bits_left = 0; + goto no_more_bits1; + } + } + else + { + i32 = cur_byte; + d32 |= i32 >> (8 - tmp); + } + } + no_more_bits1: + #endif + + if (!copy_offset) + { + continue; + } + + /* + ** compute Length of Match + */ + + /* + lengh of match Encoding (binary header + LoM bits + -------------- ---------------------------------- + 3 0 + 4..7 10 + 2 lower bits of LoM + 8..15 110 + 3 lower bits of LoM + 16..31 1110 + 4 lower bits of LoM + 32..63 1111-0 + 5 lower bits of LoM + 64..127 1111-10 + 6 lower bits of LoM + 128..255 1111-110 + 7 lower bits of LoM + 256..511 1111-1110 + 8 lower bits of LoM + 512..1023 1111-1111-0 + 9 lower bits of LoM + 1024..2047 1111-1111-10 + 10 lower bits of LoM + 2048..4095 1111-1111-110 + 11 lower bits of LoM + 4096..8191 1111-1111-1110 + 12 lower bits of LoM + 8192..16383 1111-1111-1111-0 + 13 lower bits of LoM + 16384..32767 1111-1111-1111-10 + 14 lower bits of LoM + 32768..65535 1111-1111-1111-110 + 15 lower bits of LoM + */ + + if ((d32 & 0x80000000) == 0) + { + /* lom is fixed to 3 */ + mprintf("decompress_rdp_5: LoM fixed to 3\n"); + lom = 3; + d32 <<= 1; + bits_left -= 1; + } + else if ((d32 & 0xc0000000) == 0x80000000) + { + /* 2 lower bits of LoM */ + mprintf("decompress_rdp_5: LoM : 2 bits\n"); + lom = ((d32 >> 28) & 0x03) + 4; + d32 <<= 4; + bits_left -= 4; + } + else if ((d32 & 0xe0000000) == 0xc0000000) + { + /* 3 lower bits of LoM */ + mprintf("decompress_rdp_5: LoM : 3 bits\n"); + lom = ((d32 >> 26) & 0x07) + 8; + d32 <<= 6; + bits_left -= 6; + } + else if ((d32 & 0xf0000000) == 0xe0000000) + { + /* 4 lower bits of LoM */ + mprintf("decompress_rdp_5: LoM : 4 bits\n"); + lom = ((d32 >> 24) & 0x0f) + 16; + d32 <<= 8; + bits_left -= 8; + } + else if ((d32 & 0xf8000000) == 0xf0000000) + { + /* 5 lower bits of LoM */ + mprintf("decompress_rdp_5: LoM : 5 bits\n"); + lom = ((d32 >> 22) & 0x1f) + 32; + d32 <<= 10; + bits_left -= 10; + } + else if ((d32 & 0xfc000000) == 0xf8000000) + { + /* 6 lower bits of LoM */ + mprintf("decompress_rdp_5: LoM : 6 bits\n"); + lom = ((d32 >> 20) & 0x3f) + 64; + d32 <<= 12; + bits_left -= 12; + } + else if ((d32 & 0xfe000000) == 0xfc000000) + { + /* 7 lower bits of LoM */ + mprintf("decompress_rdp_5: LoM : 7 bits\n"); + lom = ((d32 >> 18) & 0x7f) + 128; + d32 <<= 14; + bits_left -= 14; + } + else if ((d32 & 0xff000000) == 0xfe000000) + { + /* 8 lower bits of LoM */ + mprintf("decompress_rdp_5: LoM : 8 bits\n"); + lom = ((d32 >> 16) & 0xff) + 256; + d32 <<= 16; + bits_left -= 16; + } + else if ((d32 & 0xff800000) == 0xff000000) + { + /* 9 lower bits of LoM */ + mprintf("decompress_rdp_5: LoM : 9 bits\n"); + lom = ((d32 >> 14) & 0x1ff) + 512; + d32 <<= 18; + bits_left -= 18; + } + else if ((d32 & 0xffc00000) == 0xff800000) + { + /* 10 lower bits of LoM */ + mprintf("decompress_rdp_5: LoM : 10 bits\n"); + lom = ((d32 >> 12) & 0x3ff) + 1024; + d32 <<= 20; + bits_left -= 20; + } + else if ((d32 & 0xffe00000) == 0xffc00000) + { + /* 11 lower bits of LoM */ + mprintf("decompress_rdp_5: LoM : 11 bits\n"); + lom = ((d32 >> 10) & 0x7ff) + 2048; + d32 <<= 22; + bits_left -= 22; + } + else if ((d32 & 0xfff00000) == 0xffe00000) + { + /* 12 lower bits of LoM */ + mprintf("decompress_rdp_5: LoM : 12 bits\n"); + lom = ((d32 >> 8) & 0xfff) + 4096; + d32 <<= 24; + bits_left -= 24; + } + else if ((d32 & 0xfff80000) == 0xfff00000) + { + /* 13 lower bits of LoM */ + mprintf("decompress_rdp_5: LoM : 13 bits\n"); + lom = ((d32 >> 6) & 0x1fff) + 8192; + d32 <<= 26; + bits_left -= 26; + } + else if ((d32 & 0xfffc0000) == 0xfff80000) + { + /* 14 lower bits of LoM */ + mprintf("decompress_rdp_5: LoM : 14 bits\n"); + lom = ((d32 >> 4) & 0x3fff) + 16384; + d32 <<= 28; + bits_left -= 28; + } + else if ((d32 & 0xfffe0000) == 0xfffc0000) + { + /* 15 lower bits of LoM */ + mprintf("decompress_rdp_5: LoM : 15 bits\n"); + lom = ((d32 >> 2) & 0x7fff) + 32768; + d32 <<= 30; + bits_left -= 30; + } + + /* now that we have copy_offset and LoM, process them */ + + mprintf("decompress_rdp_5: Length of Match = %d\n", lom); + + src_ptr = history_ptr - copy_offset; + while (lom > 0) + { + *history_ptr++ = *src_ptr++; + lom--; + } + + /* + ** get more bits before we restart the loop + */ + + /* how may bits do we need to get? */ + tmp = 32 - bits_left; + + while (tmp) + { + if (cur_bits_left < tmp) + { + /* we have less bits than we need */ + i32 = cur_byte >> (8 - cur_bits_left); + d32 |= i32 << ((32 - bits_left) - cur_bits_left); + bits_left += cur_bits_left; + tmp -= cur_bits_left; + if (cptr < cbuf + len) + { + /* more compressed data available */ + cur_byte = *cptr++; + cur_bits_left = 8; + } + else + { + /* no more compressed data available */ + tmp = 0; + cur_bits_left = 0; + } + } + else if (cur_bits_left > tmp) + { + /* we have more bits than we need */ + d32 |= cur_byte >> (8 - tmp); + cur_byte <<= tmp; + cur_bits_left -= tmp; + bits_left = 32; + break; + } + else + { + /* we have just the right amount of bits */ + d32 |= cur_byte >> (8 - tmp); + bits_left = 32; + if (cptr < cbuf + len) + { + cur_byte = *cptr++; + cur_bits_left = 8; + } + else + { + cur_bits_left = 0; + } + break; + } + } + + } /* end while (cptr < cbuf + len) */ + + *rlen = history_ptr - rdp->mppc->history_ptr; + rdp->mppc->history_ptr = history_ptr; + mprintf("decompress_rdp_5: roff=%d rlen=%d\n", *roff, *rlen); + return True; +} + +/** + * decompress RDP 6 data + * + * @param rdp per session information + * @param cbuf compressed data + * @param len length of compressed data + * @param ctype compression flags + * @param roff starting offset of uncompressed data + * @param rlen length of uncompressed data + * + * @return True on success, False on failure + */ + +int decompress_rdp_6(rdpRdp *rdp, + uint8 *cbuf, + int len, + int ctype, + uint32 *roff, + uint32 *rlen) +{ + return False; +} + +/** + * decompress RDP 6.1 data + * + * @param rdp per session information + * @param cbuf compressed data + * @param len length of compressed data + * @param ctype compression flags + * @param roff starting offset of uncompressed data + * @param rlen length of uncompressed data + * + * @return True on success, False on failure + */ + +int decompress_rdp_61(rdpRdp *rdp, + uint8 *cbuf, + int len, + int ctype, + uint32 *roff, + uint32 *rlen) +{ + return False; +} + /* LK_TODO */ #ifdef USE_RDP_4 -int -decompress_rdp_4(char *cbuf, int len, int ctype) +int decompress_rdp_4(rdpRdp *rdp, + uint8 *cbuf, + int len, + int ctype, + uint32 *roff, + uint32 *rlen) { uint32 d32; /* we process 4 compressed bytes at a time */ uint16 copy_offset; /* location to copy data from */ @@ -42,6 +669,12 @@ decompress_rdp_4(char *cbuf, int len, int ctype) int tmp; uint32 i32; + if ((ctype & 0x0f) != PACKET_COMPR_TYPE_8K) + { + /* this is not RDP 4 compressed data */ + return False; + } + src_ptr = 0; cptr = cbuf; copy_offset = 0; @@ -371,479 +1004,54 @@ decompress_rdp_4(char *cbuf, int len, int ctype) #endif /** - * decompress RDP 5 data + * allocate space to store history buffer * - * @param rdp per session information - * @param cbuf compressed data - * @param len length of compressed data - * @param ctype compression flags - * @param roff starting offset of uncompressed data - * @param rlen length of uncompressed data - * - * @return True on success, False on failure + * @param rdp rdp struct that contains rdp_mppc struct + * @return pointer to new struct, or NULL on failure */ -int decompress_rdp_5(rdpRdp *rdp, - uint8 *cbuf, - int len, - int ctype, - uint32 *roff, - uint32 *rlen) +struct rdp_mppc *mppc_new(rdpRdp *rdp) { - uint8 *history_buf; /* uncompressed data goes here */ - uint8 *history_ptr; /* points to next free slot in bistory_buf */ - uint32 d32; /* we process 4 compressed bytes at a time */ - uint16 copy_offset; /* location to copy data from */ - uint16 lom; /* length of match */ - uint8 *src_ptr; /* used while copying compressed data */ - uint8 *cptr; /* points to next byte in cbuf */ - uint8 cur_byte; /* last byte fetched from cbuf */ - int bits_left; /* bits left in d32 for processing */ - int cur_bits_left; /* bits left in cur_byte for processing */ - int tmp; - uint32 i32; + struct rdp_mppc *ptr; - src_ptr = 0; - cptr = cbuf; - copy_offset = 0; - lom = 0; - bits_left = 0; - cur_bits_left = 0; - d32 = 0; - cur_byte = 0; - - /* get start of history buffer */ - history_buf = rdp->mppc->history_buf; - - /* get next free slot in history buffer */ - history_ptr = rdp->mppc->history_ptr; - - if (ctype & PACKET_AT_FRONT) + ptr = (struct rdp_mppc *) malloc(sizeof (struct rdp_mppc)); + if (!ptr) { - /* place compressed data at start of history buffer */ - history_ptr = rdp->mppc->history_buf; + printf("mppc_new(): system out of memory\n"); + return NULL; } - if (ctype & PACKET_FLUSHED) + ptr->history_buf = (uint8 *) malloc(RDP5_HISTORY_BUF_SIZE); + if (!ptr->history_buf) { - /* re-init history buffer */ - history_ptr = rdp->mppc->history_buf; - memset(history_buf, 0, RDP5_HISTORY_BUF_SIZE); + printf("mppc_new(): system out of memory\n"); + free(ptr); + return NULL; } - if ((ctype & PACKET_COMPRESSED) != PACKET_COMPRESSED) - { - /* data in cbuf is not compressed - copy to history buf as is */ - memcpy(history_ptr, cbuf, len); - history_ptr += len; - rdp->mppc->history_ptr = history_ptr; - return True; - } - - /* load initial data */ - tmp = 24; - while (cptr < cbuf + len) - { - i32 = *cptr++; - d32 |= i32 << tmp; - bits_left += 8; - tmp -= 8; - if (tmp < 0) - { - break; - } - } - - if (cptr < cbuf + len) - { - cur_byte = *cptr++; - cur_bits_left = 8; - } - else - { - cur_bits_left = 0; - } - - /* - ** start uncompressing data in cbuf - */ - - while (bits_left >= 8) - { - /* - value 0xxxxxxx = literal, not encoded - value 10xxxxxx = literal, encoded - value 11111xxx = copy offset 0 - 63 - value 11110xxx = copy offset 64 - 319 - value 1110xxxx = copy offset 320 - 2367 - value 110xxxxx = copy offset 2368+ - */ - - /* - at this point, we are guaranteed that d32 has 32 bits to - be processed, unless we have reached end of cbuf - */ - - copy_offset = 0; - - if ((d32 & 0x80000000) == 0) - { - /* got a literal */ - *history_ptr++ = d32 >> 24; - d32 <<= 8; - bits_left -= 8; - } - else if ((d32 & 0xc0000000) == 0x80000000) - { - /* got encoded literal */ - d32 <<= 2; - *history_ptr++ = (d32 >> 25) | 0x80; - d32 <<= 7; - bits_left -= 9; - } - else if ((d32 & 0xf8000000) == 0xf8000000) - { - /* got copy offset in range 0 - 63, */ - /* with 6 bit copy offset */ - d32 <<= 5; - copy_offset = d32 >> 26; - d32 <<= 6; - bits_left -= 11; - } - else if ((d32 & 0xf8000000) == 0xf0000000) - { - /* got copy offset in range 64 - 319, */ - /* with 8 bit copy offset */ - d32 <<= 5; - copy_offset = d32 >> 24; - copy_offset += 64; - d32 <<= 8; - bits_left -= 13; - } - else if ((d32 & 0xf0000000) == 0xe0000000) - { - /* got copy offset in range 320 - 2367, */ - /* with 11 bits copy offset */ - d32 <<= 4; - copy_offset = d32 >> 21; - copy_offset += 320; - d32 <<= 11; - bits_left -= 15; - } - else if ((d32 & 0xe0000000) == 0xc0000000) - { - /* got copy offset in range 2368+, */ - /* with 16 bits copy offset */ - d32 <<= 3; - copy_offset = d32 >> 16; - copy_offset += 2368; - d32 <<= 16; - bits_left -= 19; - } - - /* - ** get more bits before we process length of match - */ - -#if 1 - /* how may bits do we need to get? */ - tmp = 32 - bits_left; - - while (tmp) - { - if (cur_bits_left < tmp) - { - /* we have less bits than we need */ - i32 = cur_byte >> (8 - cur_bits_left); - d32 |= i32 << ((32 - bits_left) - cur_bits_left); - bits_left += cur_bits_left; - tmp -= cur_bits_left; - if (cptr < cbuf + len) - { - /* more compressed data available */ - cur_byte = *cptr++; - cur_bits_left = 8; - } - else - { - /* no more compressed data available */ - tmp = 0; - cur_bits_left = 0; - } - } - else if (cur_bits_left > tmp) - { - /* we have more bits than we need */ - d32 |= cur_byte >> (8 - tmp); - cur_byte <<= tmp; - cur_bits_left -= tmp; - bits_left = 32; - break; - } - else - { - /* we have just the right amount of bits */ - d32 |= cur_byte >> (8 - tmp); - bits_left = 32; - if (cptr < cbuf + len) - { - cur_byte = *cptr++; - cur_bits_left = 8; - } - else - { - cur_bits_left = 0; - } - break; - } - } - #else - // optimization code under development - - // LK_TODO either use only i32 or make cur_byte uint32_t - // make cbuf + len a const variable so we dont compute it - // each time - - /* if there are no more bits to get, skip this */ - if (!cur_bits_left) - { - goto no_more_bits1; - } - - /* how may bits do we need to get? */ - tmp = 32 - bits_left; - - while (tmp) - { - if (tmp > 8) - { - i32 = cur_byte; - d32 |= i32 << (24 - bits_left); - bits_left += cur_bits_left; - tmp -= cur_bits_left; - if (cptr < cbuf + len) - { - cur_byte = *cptr++; - cur_bits_left = 8; - } - else - { - cur_bits_left = 0; - goto no_more_bits1; - } - } - else - { - i32 = cur_byte; - d32 |= i32 >> (8 - tmp); - } - } - no_more_bits1: - #endif - - if (!copy_offset) - { - continue; - } - - /* - ** compute Length of Match - */ - - /* - lengh of match Encoding (binary header + LoM bits - -------------- ---------------------------------- - 3 0 - 4..7 10 + 2 lower bits of LoM - 8..15 110 + 3 lower bits of LoM - 16..31 1110 + 4 lower bits of LoM - 32..63 1111-0 + 5 lower bits of LoM - 64..127 1111-10 + 6 lower bits of LoM - 128..255 1111-110 + 7 lower bits of LoM - 256..511 1111-1110 + 8 lower bits of LoM - 512..1023 1111-1111-0 + 9 lower bits of LoM - 1024..2047 1111-1111-10 + 10 lower bits of LoM - 2048..4095 1111-1111-110 + 11 lower bits of LoM - 4096..8191 1111-1111-1110 + 12 lower bits of LoM - 8192..16383 1111-1111-1111-0 + 13 lower bits of LoM - 16384..32767 1111-1111-1111-10 + 14 lower bits of LoM - 32768..65535 1111-1111-1111-110 + 15 lower bits of LoM - */ - - if ((d32 & 0x80000000) == 0) - { - /* lom is fixed to 3 */ - lom = 3; - d32 <<= 1; - bits_left -= 1; - } - else if ((d32 & 0xc0000000) == 0x80000000) - { - /* 2 lower bits of LoM */ - lom = ((d32 >> 28) & 0x03) + 4; - d32 <<= 4; - bits_left -= 4; - } - else if ((d32 & 0xe0000000) == 0xc0000000) - { - /* 3 lower bits of LoM */ - lom = ((d32 >> 26) & 0x07) + 8; - d32 <<= 6; - bits_left -= 6; - } - else if ((d32 & 0xf0000000) == 0xe0000000) - { - /* 4 lower bits of LoM */ - lom = ((d32 >> 24) & 0x0f) + 16; - d32 <<= 8; - bits_left -= 8; - } - else if ((d32 & 0xf8000000) == 0xf0000000) - { - /* 5 lower bits of LoM */ - lom = ((d32 >> 22) & 0x1f) + 32; - d32 <<= 10; - bits_left -= 10; - } - else if ((d32 & 0xfc000000) == 0xf8000000) - { - /* 6 lower bits of LoM */ - lom = ((d32 >> 20) & 0x3f) + 64; - d32 <<= 12; - bits_left -= 12; - } - else if ((d32 & 0xfe000000) == 0xfc000000) - { - /* 7 lower bits of LoM */ - lom = ((d32 >> 18) & 0x7f) + 128; - d32 <<= 14; - bits_left -= 14; - } - else if ((d32 & 0xff000000) == 0xfe000000) - { - /* 8 lower bits of LoM */ - lom = ((d32 >> 16) & 0xff) + 256; - d32 <<= 16; - bits_left -= 16; - } - else if ((d32 & 0xff800000) == 0xff000000) - { - /* 9 lower bits of LoM */ - lom = ((d32 >> 14) & 0x1ff) + 512; - d32 <<= 18; - bits_left -= 18; - } - else if ((d32 & 0xffc00000) == 0xff800000) - { - /* 10 lower bits of LoM */ - lom = ((d32 >> 12) & 0x3ff) + 1024; - d32 <<= 20; - bits_left -= 20; - } - else if ((d32 & 0xffe00000) == 0xffc00000) - { - /* 11 lower bits of LoM */ - lom = ((d32 >> 10) & 0x7ff) + 2048; - d32 <<= 22; - bits_left -= 22; - } - else if ((d32 & 0xfff00000) == 0xffe00000) - { - /* 12 lower bits of LoM */ - lom = ((d32 >> 8) & 0xfff) + 4096; - d32 <<= 24; - bits_left -= 24; - } - else if ((d32 & 0xfff80000) == 0xfff00000) - { - /* 13 lower bits of LoM */ - lom = ((d32 >> 6) & 0x1fff) + 8192; - d32 <<= 26; - bits_left -= 26; - } - else if ((d32 & 0xfffc0000) == 0xfff80000) - { - /* 14 lower bits of LoM */ - lom = ((d32 >> 4) & 0x3fff) + 16384; - d32 <<= 28; - bits_left -= 28; - } - else if ((d32 & 0xfffe0000) == 0xfffc0000) - { - /* 15 lower bits of LoM */ - lom = ((d32 >> 2) & 0x7fff) + 32768; - d32 <<= 30; - bits_left -= 30; - } - - /* now that we have copy_offset and LoM, process them */ - - src_ptr = history_ptr - copy_offset; - while (lom > 0) - { - *history_ptr++ = *src_ptr++; - lom--; - } - - /* - ** get more bits before we restart the loop - */ - - /* how may bits do we need to get? */ - tmp = 32 - bits_left; - - while (tmp) - { - if (cur_bits_left < tmp) - { - /* we have less bits than we need */ - i32 = cur_byte >> (8 - cur_bits_left); - d32 |= i32 << ((32 - bits_left) - cur_bits_left); - bits_left += cur_bits_left; - tmp -= cur_bits_left; - if (cptr < cbuf + len) - { - /* more compressed data available */ - cur_byte = *cptr++; - cur_bits_left = 8; - } - else - { - /* no more compressed data available */ - tmp = 0; - cur_bits_left = 0; - } - } - else if (cur_bits_left > tmp) - { - /* we have more bits than we need */ - d32 |= cur_byte >> (8 - tmp); - cur_byte <<= tmp; - cur_bits_left -= tmp; - bits_left = 32; - break; - } - else - { - /* we have just the right amount of bits */ - d32 |= cur_byte >> (8 - tmp); - bits_left = 32; - if (cptr < cbuf + len) - { - cur_byte = *cptr++; - cur_bits_left = 8; - } - else - { - cur_bits_left = 0; - } - break; - } - } - - } /* end while (cptr < cbuf + len) */ - - rdp->mppc->history_ptr = history_ptr; - return True; + ptr->history_ptr = ptr->history_buf; + return ptr; +} + +/** + * free history buffer + * + * @param rdp rdp struct that contains rdp_mppc struct + */ + +void mppc_free(rdpRdp *rdp) +{ + if (!rdp->mppc) + { + return; + } + + if (rdp->mppc->history_buf) + { + free(rdp->mppc->history_buf); + rdp->mppc->history_buf = NULL; + rdp->mppc->history_ptr = NULL; + } + free(rdp->mppc); } diff --git a/libfreerdp-core/mppc.h b/libfreerdp-core/mppc.h index 6482d55b6..4c7247d5e 100644 --- a/libfreerdp-core/mppc.h +++ b/libfreerdp-core/mppc.h @@ -22,6 +22,14 @@ #include +#define _MPPC_DEBUG + +#ifdef MPPC_DEBUG +#define mprintf(y...) printf(y); +#else +#define mprintf(y...) +#endif + #define RDP5_HISTORY_BUF_SIZE 65536 struct rdp_mppc @@ -31,6 +39,12 @@ struct rdp_mppc }; // forward declarations +int decompress_rdp(rdpRdp *, uint8 *, int, int, uint32 *, uint32 *); +int decompress_rdp_4(rdpRdp *, uint8 *, int, int, uint32 *, uint32 *); int decompress_rdp_5(rdpRdp *, uint8 *, int, int, uint32 *, uint32 *); +int decompress_rdp_6(rdpRdp *, uint8 *, int, int, uint32 *, uint32 *); +int decompress_rdp_61(rdpRdp *, uint8 *, int, int, uint32 *, uint32 *); +struct rdp_mppc *mppc_new(rdpRdp *rdp); +void mppc_free(rdpRdp *rdp); #endif diff --git a/libfreerdp-core/peer.c b/libfreerdp-core/peer.c index 529bc1d62..783b6f2ef 100644 --- a/libfreerdp-core/peer.c +++ b/libfreerdp-core/peer.c @@ -59,8 +59,11 @@ static boolean peer_recv_data_pdu(rdpPeer* peer, STREAM* s) uint8 type; uint16 length; uint32 share_id; + uint8 compressed_type; + uint16 compressed_len; - if (!rdp_read_share_data_header(s, &length, &type, &share_id)) + + if (!rdp_read_share_data_header(s, &length, &type, &share_id, &compressed_type, &compressed_len)) return False; switch (type) diff --git a/libfreerdp-core/rdp.c b/libfreerdp-core/rdp.c index bfddc9cad..c12c3c3ce 100644 --- a/libfreerdp-core/rdp.c +++ b/libfreerdp-core/rdp.c @@ -113,7 +113,8 @@ void rdp_write_share_control_header(STREAM* s, uint16 length, uint16 type, uint1 stream_write_uint16(s, channel_id); /* pduSource */ } -boolean rdp_read_share_data_header(STREAM* s, uint16* length, uint8* type, uint32* share_id) +boolean rdp_read_share_data_header(STREAM* s, uint16* length, uint8* type, uint32* share_id, + uint8 *compressed_type, uint16 *compressed_len) { if (stream_get_left(s) < 12) return False; @@ -124,8 +125,16 @@ boolean rdp_read_share_data_header(STREAM* s, uint16* length, uint8* type, uint3 stream_seek_uint8(s); /* streamId (1 byte) */ stream_read_uint16(s, *length); /* uncompressedLength (2 bytes) */ stream_read_uint8(s, *type); /* pduType2, Data PDU Type (1 byte) */ - stream_seek_uint8(s); /* compressedType (1 byte) */ - stream_seek_uint16(s); /* compressedLength (2 bytes) */ + if (*type & 0x80) + { + stream_read_uint8(s, *compressed_type); /* compressedType (1 byte) */ + stream_read_uint16(s, *compressed_len); /* compressedLength (2 bytes) */ + } + else + { + *compressed_type = 0; + *compressed_len = 0; + } return True; } @@ -304,8 +313,10 @@ void rdp_recv_data_pdu(rdpRdp* rdp, STREAM* s) uint8 type; uint16 length; uint32 share_id; + uint8 compressed_type; + uint16 compressed_len; - rdp_read_share_data_header(s, &length, &type, &share_id); + rdp_read_share_data_header(s, &length, &type, &share_id, &compressed_type, &compressed_len); if (type != DATA_PDU_TYPE_UPDATE) printf("recv %s Data PDU (0x%02X), length:%d\n", DATA_PDU_TYPE_STRINGS[type], type, length); @@ -576,6 +587,7 @@ rdpRdp* rdp_new(freerdp* instance) rdp->nego = nego_new(rdp->transport); rdp->mcs = mcs_new(rdp->transport); rdp->vchan = vchan_new(instance); + rdp->mppc = mppc_new(rdp); } return rdp; @@ -600,6 +612,7 @@ void rdp_free(rdpRdp* rdp) mcs_free(rdp->mcs); vchan_free(rdp->vchan); xfree(rdp); + mppc_free(rdp); } } diff --git a/libfreerdp-core/rdp.h b/libfreerdp-core/rdp.h index fa773b6fa..0384ba93f 100644 --- a/libfreerdp-core/rdp.h +++ b/libfreerdp-core/rdp.h @@ -124,7 +124,7 @@ struct rdp_rdp struct rdp_settings* settings; struct rdp_transport* transport; struct rdp_vchan* vchan; - struct rdp_mppc* mppc; + struct rdp_mppc* mppc; }; void rdp_read_security_header(STREAM* s, uint16* flags); @@ -133,7 +133,9 @@ void rdp_write_security_header(STREAM* s, uint16 flags); boolean rdp_read_share_control_header(STREAM* s, uint16* length, uint16* type, uint16* channel_id); void rdp_write_share_control_header(STREAM* s, uint16 length, uint16 type, uint16 channel_id); -boolean rdp_read_share_data_header(STREAM* s, uint16* length, uint8* type, uint32* share_id); +boolean rdp_read_share_data_header(STREAM* s, uint16* length, uint8* type, uint32* share_id, + uint8 *compressed_type, uint16 *compressed_len); + void rdp_write_share_data_header(STREAM* s, uint16 length, uint8 type, uint32 share_id); STREAM* rdp_send_stream_init(rdpRdp* rdp); diff --git a/libfreerdp-core/update.c b/libfreerdp-core/update.c index b63e4b8a0..98ccaa23f 100644 --- a/libfreerdp-core/update.c +++ b/libfreerdp-core/update.c @@ -294,13 +294,15 @@ void update_recv(rdpUpdate* update, STREAM* s) uint16 length; uint16 source; uint32 shareId; + uint8 compressed_type; + uint16 compressed_len; rdp_read_share_control_header(s, &length, &pduType, &source); if (pduType != PDU_TYPE_DATA) return; - rdp_read_share_data_header(s, &length, &type, &shareId); + rdp_read_share_data_header(s, &length, &type, &shareId, &compressed_type, &compressed_len); if (type == DATA_PDU_TYPE_UPDATE) update_recv(update, s);