def parse(s: BytesIO, flags: int) -> CacheBitmap: self = CacheBitmapV3(3) self.cacheId = flags & 0x00000003 self.flags = (flags & 0x0000FF80) >> 7 bitsPerPixelId = (flags & 0x00000078) >> 3 # The spec says this should never be 0, but it is... self.bpp = CBR23_BPP[bitsPerPixelId] self.cacheIndex = Uint16LE.unpack(s) self.key1 = Uint32LE.unpack(s) self.key2 = Uint32LE.unpack(s) self.bpp = Uint8.unpack(s) compressed = Uint8.unpack(s) s.read(1) # Reserved (1 bytes) self.codecId = Uint8.unpack(s) self.width = Uint16LE.unpack(s) self.height = Uint16LE.unpack(s) dataLen = Uint32LE.unpack(s) if compressed: # TS_COMPRESSED_BITMAP_HEADER_EX present. s.read(24) # Non-essential. self.data = s.read(dataLen) return self
def parse(s: BytesIO, flags: int, glyph: GlyphSupport) -> 'CacheGlyph': """ Parse a CACHE_GLYPH order. :param s: The byte stream to parse :param flags: The UPDATE PDU controlFlags :param glyph: One of Glyph or GlyphV2 classes to select the parsing strategy """ self = CacheGlyph() if GlyphSupport.GLYPH_SUPPORT_ENCODE: self.cacheId = flags & 0x0F cGlyphs = flags >> 8 unicodePresent = (flags >> 4 & 0x0F) & 0x01 self.glyphs = [GlyphV2.parse(s) for _ in range(cGlyphs)] else: self.cacheId = Uint8.unpack(s) cGlyphs = Uint8.unpack(s) unicodePresent = flags & CG_GLYPH_UNICODE_PRESENT self.glyphs = [Glyph.parse(s) for _ in range(cGlyphs)] if unicodePresent and cGlyphs > 0: self.unicode = read_utf16_str(s, cGlyphs) return self
def update(self, s: BytesIO): if self.ctx.field(1): self.nLeftRect = read_coord(s, self.ctx.deltaCoords, self.nLeftRect) if self.ctx.field(2): self.nTopRect = read_coord(s, self.ctx.deltaCoords, self.nTopRect) if self.ctx.field(3): self.nWidth = read_coord(s, self.ctx.deltaCoords, self.nWidth) if self.ctx.field(4): self.nHeight = read_coord(s, self.ctx.deltaCoords, self.nHeight) if self.ctx.field(5): r = Uint8.unpack(s) self.color = (self.color & 0x00FFFF00) | r if self.ctx.field(6): g = Uint8.unpack(s) self.color = (self.color & 0x00FF00FF) | (g << 8) if self.ctx.field(7): b = Uint8.unpack(s) self.color = (self.color & 0x0000FFFF) | (b << 16) if self.ctx.field(8): self.numRectangles = Uint8.unpack(s) if self.ctx.field(9): self.cbData = Uint16LE.unpack(s) self.rectangles = read_delta_rectangles(s, self.numRectangles) return self
def update(self, s: BytesIO): num = self.numPoints if self.ctx.field(1): self.x0 = read_coord(s, self.ctx.deltaCoords, self.x0) if self.ctx.field(2): self.y0 = read_coord(s, self.ctx.deltaCoords, self.y0) if self.ctx.field(3): self.rop2 = Uint8.unpack(s) if self.ctx.field(4): self.fillMode = Uint8.unpack(s) if self.ctx.field(5): self.bg = read_rgb(s) if self.ctx.field(6): self.fg = read_rgb(s) self.brush.update(s, self.ctx.fieldFlags >> 6) if self.ctx.field(12): num = Uint8.unpack(s) if self.ctx.field(13): self.cbData = Uint8.unpack(s) self.numPoints = num self.points = read_delta_points(s, self.numPoints, self.x0, self.y0) self.bgMode = BACKMODE_TRANSPARENT if self.rop2 & 0x80 else BACKMODE_OPAQUE self.rop2 = self.rop2 & 0x1F return self
def update(self, s: BytesIO): if self.ctx.field(1): self.x = read_coord(s, self.ctx.deltaCoords, self.x) if self.ctx.field(2): self.y = read_coord(s, self.ctx.deltaCoords, self.y) if self.ctx.field(3): self.w = read_coord(s, self.ctx.deltaCoords, self.w) if self.ctx.field(4): self.h = read_coord(s, self.ctx.deltaCoords, self.h) if self.ctx.field(5): self.rop = Uint8.unpack(s) if self.ctx.field(6): self.bg = read_rgb(s) if self.ctx.field(7): self.fg = read_rgb(s) self.brush.update(s, self.ctx.fieldFlags >> 7) if self.ctx.field(13): self.numRectangles = Uint8.unpack(s) if self.ctx.field(14): self.cbData = Uint16LE.unpack(s) self.rectangles = read_delta_rectangles(s, self.numRectangles) return self
def update(self, s: BytesIO): if self.ctx.field(1): self.nLeftRect = read_coord(s, self.ctx.deltaCoords, self.nLeftRect) if self.ctx.field(2): self.nTopRect = read_coord(s, self.ctx.deltaCoords, self.nTopRect) if self.ctx.field(3): self.nWidth = read_coord(s, self.ctx.deltaCoords, self.nWidth) if self.ctx.field(4): self.nHeight = read_coord(s, self.ctx.deltaCoords, self.nHeight) if self.ctx.field(5): self.bRop = Uint8.unpack(s) if self.ctx.field(6): self.nXSrc = read_coord(s, self.ctx.deltaCoords, self.nXSrc) if self.ctx.field(7): self.nYSrc = read_coord(s, self.ctx.deltaCoords, self.nYSrc) if self.ctx.field(8): self.numRectangles = Uint8.unpack(s) if self.ctx.field(9): self.cbData = Uint16LE.unpack(s) self.rectangles = read_delta_rectangles(s, self.numRectangles) return self
def read_encoded_uint16(s: BytesIO) -> int: """Read an encoded UINT16.""" # 2.2.2.2.1.2.1.2 b = Uint8.unpack(s) if b & 0x80: return (b & 0x7F) << 8 | Uint8.unpack(s) else: return b & 0x7F
def read_encoded_int16(s: BytesIO) -> int: # 2.2.2.2.1.2.1.3 msb = Uint8.unpack(s) val = msb & 0x3F if msb & 0x80: lsb = Uint8.unpack(s) val = (val << 8) | lsb return -val if msb & 0x40 else val
def readLength(s: BinaryIO) -> int: """ Unpack a PER length indicator :param s: stream """ byte = Uint8.unpack(s.read(1)) if byte & 0x80: byte &= ~0x80 return (byte << 8) + Uint8.unpack(s.read(1)) else: return byte
def readLength(s): """ Unpack a PER length indicator :param s: stream :type s: file :return: int """ byte = Uint8.unpack(s.read(1)) size = 0 if byte & 0x80: byte &= ~0x80 return (byte << 8) + Uint8.unpack(s.read(1)) else: return byte
def _parse_secondary(self, s: BytesIO, flags: int): Uint16LE.unpack(s) # orderLength (unused) extraFlags = Uint16LE.unpack(s) orderType = Uint8.unpack(s) assert orderType >= 0 and orderType < len(_sec) _sec[orderType](self, s, orderType, extraFlags)
def update(self, s: BytesIO): if self.ctx.field(1): self.cacheId = Uint16LE.unpack(s) if self.ctx.field(2): self.left = read_coord(s, self.ctx.deltaCoords, self.left) if self.ctx.field(3): self.top = read_coord(s, self.ctx.deltaCoords, self.top) if self.ctx.field(4): self.width = read_coord(s, self.ctx.deltaCoords, self.width) if self.ctx.field(5): self.height = read_coord(s, self.ctx.deltaCoords, self.height) if self.ctx.field(6): self.rop = Uint8.unpack(s) if self.ctx.field(7): self.nXSrc = read_coord(s, self.ctx.deltaCoords, self.nXSrc) if self.ctx.field(8): self.nYSrc = read_coord(s, self.ctx.deltaCoords, self.nYSrc) if self.ctx.field(9): self.bg = read_rgb(s) if self.ctx.field(10): self.fg = read_rgb(s) self.brush.update(s, self.ctx.fieldFlags >> 10) if self.ctx.field(16): self.cacheIndex = Uint16LE.unpack(s) self.colorIndex = self.cacheId >> 8 self.cacheId = self.cacheId & 0xFF return self
def update(self, s: BytesIO) -> 'MemBlt': ctx = self.ctx if ctx.field(1): self.cacheId = Uint16LE.unpack(s) if ctx.field(2): self.left = read_coord(s, ctx.deltaCoords, self.left) if ctx.field(3): self.top = read_coord(s, ctx.deltaCoords, self.top) if ctx.field(4): self.width = read_coord(s, ctx.deltaCoords, self.width) if ctx.field(5): self.height = read_coord(s, ctx.deltaCoords, self.height) if ctx.field(6): self.rop = Uint8.unpack(s) if ctx.field(7): self.xSrc = read_coord(s, ctx.deltaCoords, self.xSrc) if ctx.field(8): self.ySrc = read_coord(s, ctx.deltaCoords, self.ySrc) if ctx.field(9): self.cacheIndex = Uint16LE.unpack(s) self.colorIndex = self.cacheId >> 8 self.cacheId = self.cacheId & 0xFF return self
def update(self, s: BytesIO, flags: int): """ Update the context when parsing a new primary order. This method should be called at the beginning of every new primary order to process contextual changes. :param s BytesIO: The raw byte stream :param flags int: The controlFlags received in the UPDATE PDU. :return: The orderType to act upon. """ if flags & ControlFlags.TS_TYPE_CHANGE: self.orderType = Uint8.unpack(s) assert self.orderType is not None self.fieldFlags = read_field_flags(s, flags, self.orderType) # Process bounding rectangle updates if flags & ControlFlags.TS_BOUNDS: self.bounded = True if not flags & ControlFlags.TS_ZERO_BOUNDS_DELTAS: self.bounds.update(s) else: self.bounded = False self.deltaCoords = flags & ControlFlags.TS_DELTA_COORDS != 0 return self.orderType
def readSelection(s): """ Unpack a PER selection :param s: stream :type s: file :return: int """ return Uint8.unpack(s.read(1))
def readEnumeration(s): """ Unpack a PER enumeration format :param s: stream :type s: file :return: int """ return Uint8.unpack(s.read(1))
def update(self, s: BytesIO): if self.ctx.field(1): self.cacheId = Uint8.unpack(s) if self.ctx.field(2): self.ulCharInc = Uint8.unpack(s) self.flAccel = Uint8.unpack(s) if self.ctx.field(3): self.bg = read_rgb(s) if self.ctx.field(4): self.fg = read_rgb(s) if self.ctx.field(5): self.bkLeft = read_coord(s, self.ctx.deltaCoords, self.bkLeft) if self.ctx.field(6): self.bkTop = read_coord(s, self.ctx.deltaCoords, self.bkTop) if self.ctx.field(7): self.bkRight = read_coord(s, self.ctx.deltaCoords, self.bkRight) if self.ctx.field(8): self.bkBottom = read_coord(s, self.ctx.deltaCoords, self.bkBottom) if self.ctx.field(9): self.opLeft = read_coord(s, self.ctx.deltaCoords, self.opLeft) if self.ctx.field(10): self.opTop = read_coord(s, self.ctx.deltaCoords, self.opTop) if self.ctx.field(11): self.opRight = read_coord(s, self.ctx.deltaCoords, self.opRight) if self.ctx.field(12): self.opBottom = read_coord(s, self.ctx.deltaCoords, self.opBottom) if self.ctx.field(13): self.x = read_coord(s, self.ctx.deltaCoords, self.x) if self.ctx.field(14): self.y = read_coord(s, self.ctx.deltaCoords, self.y) if self.ctx.field(15): cbData = Uint8.unpack(s) if cbData > 1: # Read glyph data. self.glyph = GlyphV2.parse(s) self.cacheIndex = self.glyph.cacheIndex s.read(2) # Padding / Unicode representation else: # Only a cache index. assert cbData == 1 self.glyph = None # Glyph must be retrieved from cacheIndex self.cacheIndex = Uint8.unpack(s) return self
def readChoice(s): """ Unpack a PER choice :param s: stream :type s: file :return: int """ return Uint8.unpack(s.read(1))
def readNumberOfSet(s): """ Unpack a PER NumberOfSet :param s: stream :type s: file :return: int """ return Uint8.unpack(s.read(1))
def update(self, s: BytesIO): if self.ctx.field(1): self.left = read_coord(s, self.ctx.deltaCoords, self.left) if self.ctx.field(2): self.top = read_coord(s, self.ctx.deltaCoords, self.top) if self.ctx.field(3): self.right = read_coord(s, self.ctx.deltaCoords, self.right) if self.ctx.field(4): self.bottom = read_coord(s, self.ctx.deltaCoords, self.bottom) if self.ctx.field(5): self.rop2 = Uint8.unpack(s) if self.ctx.field(6): self.fillMode = Uint8.unpack(s) if self.ctx.field(7): self.color = read_rgb(s) return self
def _parse_order(self, s: BytesIO): controlFlags = Uint8.unpack(s) if not (controlFlags & ControlFlags.TS_STANDARD): self._parse_altsec(s, controlFlags) elif (controlFlags & ControlFlags.TS_SECONDARY): self._parse_secondary(s, controlFlags) else: self._parse_primary(s, controlFlags)
def readUniversalTag(s: BinaryIO, tag: Tag, isConstruct: bool) -> bool: """ Unpack universal tag and return True if the proper tag was read. :param s: stream :param tag: BER tag :param isConstruct: True if a construct is expected """ byte = Uint8.unpack(s.read(1)) return byte == ((Class.BER_CLASS_UNIV | berPC(isConstruct)) | (Tag.BER_TAG_MASK & tag))
def readObjectIdentifier(s: BinaryIO): """ Unpack a PER object identifier (tuple of 6 integers) :param s: stream :return: (int, int, int, int, int, int) """ size = readLength(s) if size != 5: raise ValueError("Object identifier size must be 5 (got %d instead)" % size) a_oid = [0, 0, 0, 0, 0, 0] t12 = Uint8.unpack(s.read(1)) a_oid[0] = t12 >> 4 a_oid[1] = t12 & 0x0f a_oid[2] = Uint8.unpack(s.read(1)) a_oid[3] = Uint8.unpack(s.read(1)) a_oid[4] = Uint8.unpack(s.read(1)) a_oid[5] = Uint8.unpack(s.read(1)) return tuple(a_oid)
def parse(s: BytesIO) -> 'CacheColorTable': self = CacheColorTable() self.cacheIndex = Uint8.unpack(s) numberColors = Uint16LE.unpack(s) assert numberColors == 256 self.colors = [read_color(s) for _ in range(numberColors)] return self
def update(self, s: BytesIO): if self.ctx.field(1): self.cacheId = Uint8.unpack(s) if self.ctx.field(2): self.flAccel = Uint8.unpack(s) if self.ctx.field(3): self.ulCharInc = Uint8.unpack(s) if self.ctx.field(4): self.fOpRedundant = Uint8.unpack(s) if self.ctx.field(5): self.bg = read_rgb(s) if self.ctx.field(6): self.fg = read_rgb(s) if self.ctx.field(7): self.bkLeft = Uint16LE.unpack(s) if self.ctx.field(8): self.bkTop = Uint16LE.unpack(s) if self.ctx.field(9): self.bkRight = Uint16LE.unpack(s) if self.ctx.field(10): self.bkBottom = Uint16LE.unpack(s) if self.ctx.field(11): self.opLeft = Uint16LE.unpack(s) if self.ctx.field(12): self.opTop = Uint16LE.unpack(s) if self.ctx.field(13): self.opRight = Uint16LE.unpack(s) if self.ctx.field(14): self.opBottom = Uint16LE.unpack(s) self.brush.update(s, self.ctx.fieldFlags >> 14) if self.ctx.field(20): self.x = Uint16LE.unpack(s) if self.ctx.field(21): self.y = Uint16LE.unpack(s) if self.ctx.field(22): cbData = Uint8.unpack(s) self.data = s.read(cbData) return self
def update(self, s: BytesIO, flags: int): if flags & 0b00001: self.x = Uint8.unpack(s) if flags & 0b00010: self.y = Uint8.unpack(s) if flags & 0b00100: self.style = Uint8.unpack(s) if flags & 0b01000: self.hatch = Uint8.unpack(s) if flags & 0b10000: self.data = (s.read(7) + bytes([self.hatch]))[::-1] if self.style & CACHED_BRUSH: self.index = self.hatch self.bpp = BMF_BPP[self.style & 0x07] if self.bpp == 0: self.bpp = 1 return self
def readLength(s: BinaryIO) -> int: """ Read length of BER structure Length is on 1, 2 or 3 bytes :param s: stream """ byte = Uint8.unpack(s.read(1)) if byte & 0x80: byte &= ~0x80 if byte == 1: return Uint8.unpack(s.read(1)) elif byte == 2: return Uint16BE.unpack(s.read(2)) else: raise ValueError("BER length must be 1 or 2") else: return byte
def readEnumeration(s: BinaryIO) -> int: """ Unpack a BER enumeration value :param s: stream """ if not readUniversalTag(s, Tag.BER_TAG_ENUMERATED, False): raise ValueError("Bad enumeration tag") if readLength(s) != 1: raise ValueError("Enumeration size must be 1") return Uint8.unpack(s.read(1))
def update(self, s: BytesIO): if self.ctx.field(1): self.x = read_coord(s, self.ctx.deltaCoords, self.x) if self.ctx.field(2): self.y = read_coord(s, self.ctx.deltaCoords, self.y) if self.ctx.field(3): self.w = read_coord(s, self.ctx.deltaCoords, self.w) if self.ctx.field(4): self.h = read_coord(s, self.ctx.deltaCoords, self.h) if self.ctx.field(5): r = Uint8.unpack(s) self.color = (self.color & 0x00FFFF00) | r if self.ctx.field(6): g = Uint8.unpack(s) self.color = (self.color & 0x00FF00FF) | (g << 8) if self.ctx.field(7): b = Uint8.unpack(s) self.color = (self.color & 0x0000FFFF) | (b << 16) return self
def parse(s: BytesIO) -> Glyph: self = Glyph() self.cacheIndex = Uint8.unpack(s) self.x = read_encoded_int16(s) self.y = read_encoded_int16(s) self.w = read_encoded_uint16(s) self.h = read_encoded_uint16(s) self.data = read_glyph_bitmap(self.w, self.h, s) return self