From 149d212d93dcafda7b03d9614790074e1a1a0947 Mon Sep 17 00:00:00 2001 From: speyrefitte Date: Thu, 26 Jun 2014 18:00:29 +0200 Subject: [PATCH] rle decoding --- rdpy/display/qt.py | 16 +++--- rdpy/display/rle.py | 112 +++++++++++++++++++++++++++---------- rdpy/examples/rdpclient.py | 2 +- rdpy/network/type.py | 20 ++++++- 4 files changed, 109 insertions(+), 41 deletions(-) diff --git a/rdpy/display/qt.py b/rdpy/display/qt.py index 8fc5a12..af5288f 100644 --- a/rdpy/display/qt.py +++ b/rdpy/display/qt.py @@ -27,7 +27,7 @@ from PyQt4 import QtGui, QtCore from rdpy.protocol.rfb.rfb import RFBClientObserver from rdpy.protocol.rdp.rdp import RDPClientObserver -from rdpy.network.type import UInt16Le, Stream +from rdpy.network.type import UInt16Le, UInt24Le, Stream import rle class QAdaptor(object): @@ -118,7 +118,8 @@ class RFBClientQt(RFBClientObserver, QAdaptor): @param e: qKeyEvent ''' self.keyEvent(True, e.nativeVirtualKey()) - + + class RDPClientQt(RDPClientObserver, QAdaptor): ''' Adaptor for RDP client @@ -149,18 +150,17 @@ class RDPClientQt(RDPClientObserver, QAdaptor): @param isCompress: use RLE compression @param data: bitmap data ''' - #TODO - if isCompress: - #rle.decode("", Stream(data), width, height, UInt16Le) - return imageFormat = None if bitsPerPixel == 16: imageFormat = QtGui.QImage.Format_RGB16 + if isCompress: + data = rle.decode(Stream(data), width, height, UInt16Le).getvalue() + elif bitsPerPixel == 24: imageFormat = QtGui.QImage.Format_RGB888 - elif bitsPerPixel == 32: - imageFormat = QtGui.QImage.Format_RGB32 + if isCompress: + data = rle.decode(Stream(data), width, height, UInt24Le).getvalue() else: print "Receive image in bad format" return diff --git a/rdpy/display/rle.py b/rdpy/display/rle.py index 8b7128f..370dd0b 100644 --- a/rdpy/display/rle.py +++ b/rdpy/display/rle.py @@ -27,66 +27,66 @@ Most of bitmap in RDP protocol use this encoding @see: http://msdn.microsoft.com/en-us/library/dd240593.aspx """ -from rdpy.network.type import UInt8, UInt16Le, Stream, sizeof +from rdpy.network.type import UInt8, UInt16Le, Stream def decode(src, width, height, colorType): """ It's a python transcription of rdesktop algorithm """ - lastopcode = -1 + prevLine = None + line = None + lastopcode = None x = width - prevLine = 0 - code = UInt8() - opcode = UInt8() + insertMix = False + biColor = False color1 = colorType() color2 = colorType() - mix = colorType() + mix = ~colorType() + mask = UInt8() + fom_mask = UInt8() + code = UInt8() + opcode = UInt8() isFillOrMix = False - insertMix = False - fom_mask = 0 - mask = 0 - line = 0 + count = UInt16Le() dst = [colorType()] * width * height while src.dataLen() > 0: #compute orders - + fom_mask = UInt8() src.readType(code) opcode = code >> 4 - count = UInt16Le() - if opcode == 0xc or opcode == 0xd or opcode == 0xe: opcode -= 6 - count = code & 0xf + count.value = (code & 0xf).value offset = 16 elif opcode == 0xf: opcode = code & 0xf if opcode < 9: src.readType(count) else: - count = UInt16Le(8 if opcode < 0xb else 1) + count.value = 8 if opcode < 0xb else 1 offset = 0 else: opcode >>= 1 - count = UInt16Le((code & 0xf).value) + count.value = (code & 0x1f).value offset = 32 if offset != 0: - isFillOrMix = opcode == 2 or opcode == 7 + isFillOrMix = ((opcode == 2) or (opcode == 7)) if count == 0: tmp = UInt8() src.readType(tmp) if isFillOrMix: - count = UInt16Le((tmp + 1).value) + count.value = (tmp + 1).value else: - count = UInt16Le((tmp + offset).value) + count.value = (tmp + offset).value elif isFillOrMix: count <<= 3 if opcode == 0: - if lastopcode == opcode and not (x == width and prevLine == 0): + if not lastopcode is None and lastopcode == opcode and not ((x == width) and (prevLine is None)): insertMix = True elif opcode == 3 or opcode == 8: src.readType(color2) @@ -94,16 +94,21 @@ def decode(src, width, height, colorType): src.readType(color1) elif opcode == 6 or opcode == 7: src.readType(mix) + opcode -= 5 elif opcode == 9: - mask = 0x03 - opcode = UInt8(0x02) - fom_mask = 5 + mask.value = 0x03 + opcode.value = 0x02 + fom_mask.value = 3 + elif opcode == 0x0a: + mask.value = 0x05; + opcode.value = 0x02; + fom_mask.value = 5; lastopcode = opcode mixmask = 0 while count > 0: - if x > width: + if x >= width: if height <= 0: raise InvalidExpectedDataException("In RLE decompression height must be greater than 0") x = 0 @@ -114,7 +119,7 @@ def decode(src, width, height, colorType): #fill if opcode == 0: if insertMix: - if prevLine == 0: + if prevLine is None: dst[line + x] = mix else: dst[line + x] = dst[prevLine + x] ^ mix @@ -122,7 +127,7 @@ def decode(src, width, height, colorType): count -= 1 x += 1 - if prevLine == 0: + if prevLine is None: while count > 0 and x < width: dst[line + x] = colorType() count -= 1 @@ -134,7 +139,7 @@ def decode(src, width, height, colorType): x += 1 #mix elif opcode == 1: - if prevLine == 0: + if prevLine is None: while count > 0 and x < width: dst[line + x] = mix count -= 1 @@ -146,7 +151,42 @@ def decode(src, width, height, colorType): x += 1 #fill or mix elif opcode == 2: - pass + if prevLine is None: + while count > 0 and x < width: + + mixmask <<= 1 + if mixmask & 0xff == 0: + if fom_mask: + mask = fom_mask + else: + src.readType(mask) + mixmask = 1 + + if mask & mixmask: + dst[line + x] = mix + else: + dst[line + x] = colorType() + count -= 1 + x += 1 + else: + while count > 0 and x < width: + + mixmask <<= 1 + if mixmask & 0xff == 0: + if fom_mask: + mask = fom_mask + else: + src.readType(mask) + mixmask = 1 + + if mask & mixmask: + dst[line + x] = dst[prevLine + x] ^ mix + else: + dst[line + x] = dst[prevLine + x] + + count -= 1 + x += 1 + #color elif opcode == 3: while count > 0 and x < width: @@ -161,7 +201,16 @@ def decode(src, width, height, colorType): x += 1 #bicolor elif opcode == 8: - pass + while count > 0 and x < width: + if biColor: + dst[line + x] = color2 + biColor = False + else: + dst[line + x] = color1 + biColor = True + count += 1 + count -= 1 + x += 1 #write elif opcode == 0xd: while count > 0 and x < width: @@ -173,8 +222,9 @@ def decode(src, width, height, colorType): dst[line + x] = colorType() count -= 1 x += 1 + else: + raise InvalidExpectedDataException("In RLE decompression invalid opcode") output = Stream() output.writeType(dst) - return output - + return output \ No newline at end of file diff --git a/rdpy/examples/rdpclient.py b/rdpy/examples/rdpclient.py index 909875f..af98e75 100644 --- a/rdpy/examples/rdpclient.py +++ b/rdpy/examples/rdpclient.py @@ -45,7 +45,7 @@ class RDPClientQtFactory(rdp.ClientFactory): #create qt widget self._w = client.getWidget() self._w.resize(1024, 800) - self._w.setWindowTitle('rdpyclient-vnc') + self._w.setWindowTitle('rdpyclient-rdp') self._w.show() return client diff --git a/rdpy/network/type.py b/rdpy/network/type.py index 9f1dc4d..5228365 100644 --- a/rdpy/network/type.py +++ b/rdpy/network/type.py @@ -341,7 +341,7 @@ class SimpleType(Type, CallableValue): def __or__(self, other): ''' - implement bitwise and operator + implement bitwise or operator @param other: SimpleType value or try to construct same type as self around other value @return: self.__class__ object with or result @@ -350,6 +350,17 @@ class SimpleType(Type, CallableValue): other = self.__class__(other) return self.__class__(self.value.__or__(other.value)) + def __xor__(self, other): + ''' + implement bitwise xor operator + @param other: SimpleType value or try to construct same type as self + around other value + @return: self.__class__ object with or result + ''' + if not isinstance(other, SimpleType): + other = self.__class__(other) + return self.__class__(self.value.__xor__(other.value)) + def __lshift__(self, other): ''' left shift operator @@ -376,6 +387,13 @@ class SimpleType(Type, CallableValue): @return: hash of inner value ''' return hash(self.value) + + def __nonzero__(self): + ''' + boolean conversion + @return: bool of inner value + ''' + return bool(self.value) class CompositeType(Type):