Files
2021-10-03 00:55:57 +02:00

282 lines
9.7 KiB
Python

import io
import enum
from typing import List
from aardwolf.extensions.RDPECLIP.protocol.formatlist import CLIPBRD_FORMAT
class MAPPING_MODE(enum.Enum):
TEXT = 0x00000001 #Each logical unit is mapped to one device pixel. Positive x is to the right; positive y is down.
LOMETRIC = 0x00000002 #Each logical unit is mapped to 0.1 millimeter. Positive x is to the right; positive y is up.
HIMETRIC = 0x00000003 #Each logical unit is mapped to 0.01 millimeter. Positive x is to the right; positive y is up.
LOENGLISH = 0x00000004 #Each logical unit is mapped to 0.01 inch. Positive x is to the right; positive y is up.
HIENGLISH = 0x00000005 #Each logical unit is mapped to 0.001 inch. Positive x is to the right; positive y is up.
TWIPS = 0x00000006 #Each logical unit is mapped to 1/20 of a printer's point (1/1440 of an inch), also called a twip. Positive x is to the right; positive y is up.
ISOTROPIC = 0x00000007 #Logical units are mapped to arbitrary units with equally scaled axes; one unit along the x-axis is equal to one unit along the y-axis.
ANISOTROPIC = 0x00000008
class CLIPRDR_MFPICT:
def __init__(self):
self.mappingMode:MAPPING_MODE = None
self.xExt:int = None
self.yExt:int = None
self.metaFileData:bytes = None
def to_bytes(self):
t = self.mappingMode.value.to_bytes(4, byteorder='little', signed=False)
t += self.xExt.to_bytes(4, byteorder='little', signed=False)
t += self.yExt.to_bytes(4, byteorder='little', signed=False)
t += self.metaFileData
return t
@staticmethod
def from_bytes(bbuff: bytes):
return CLIPRDR_MFPICT.from_buffer(io.BytesIO(bbuff))
@staticmethod
def from_buffer(buff: io.BytesIO):
msg = CLIPRDR_MFPICT()
msg.mappingMode = MAPPING_MODE(int.from_bytes(buff.read(4), byteorder='little', signed=False))
msg.xExt = int.from_bytes(buff.read(4), byteorder='little', signed=False)
msg.yExt = int.from_bytes(buff.read(4), byteorder='little', signed=False)
msg.metaFileData = buff.read()
return msg
def __repr__(self):
t = '==== CLIPRDR_MFPICT ====\r\n'
for k in self.__dict__:
if isinstance(self.__dict__[k], enum.IntFlag):
value = self.__dict__[k]
elif isinstance(self.__dict__[k], enum.Enum):
value = self.__dict__[k].name
else:
value = self.__dict__[k]
t += '%s: %s\r\n' % (k, value)
return t
class PALETTEENTRY:
def __init__(self):
self.red:int = None
self.green:int = None
self.blue:int = None
self.extra:bytes = b'\x00'
def to_bytes(self):
t = self.red.to_bytes(1, byteorder='little', signed=False)
t += self.green.to_bytes(1, byteorder='little', signed=False)
t += self.blue.to_bytes(1, byteorder='little', signed=False)
t += self.extra
return t
@staticmethod
def from_bytes(bbuff: bytes):
return PALETTEENTRY.from_buffer(io.BytesIO(bbuff))
@staticmethod
def from_buffer(buff: io.BytesIO):
msg = PALETTEENTRY()
msg.red = buff.read(1)[0]
msg.green = buff.read(1)[0]
msg.blue = buff.read(1)[0]
msg.extra = buff.read(1)
return msg
def __repr__(self):
t = '==== PALETTEENTRY ====\r\n'
for k in self.__dict__:
if isinstance(self.__dict__[k], enum.IntFlag):
value = self.__dict__[k]
elif isinstance(self.__dict__[k], enum.Enum):
value = self.__dict__[k].name
else:
value = self.__dict__[k]
t += '%s: %s\r\n' % (k, value)
return t
class CLIPRDR_PALETTE:
def __init__(self):
self.paletteEntriesData:List[PALETTEENTRY] = []
def to_bytes(self):
t = b''
for pe in self.paletteEntriesData:
t += pe.to_bytes()
return t
@staticmethod
def from_bytes(bbuff: bytes):
return CLIPRDR_PALETTE.from_buffer(io.BytesIO(bbuff))
@staticmethod
def from_buffer(buff: io.BytesIO):
msg = CLIPRDR_PALETTE()
while buff.read(1) != b'':
buff.seek(-1,1)
PALETTEENTRY.from_buffer(buff)
return msg
def __repr__(self):
t = '==== CLIPRDR_PALETTE ====\r\n'
for k in self.__dict__:
if isinstance(self.__dict__[k], enum.IntFlag):
value = self.__dict__[k]
elif isinstance(self.__dict__[k], enum.Enum):
value = self.__dict__[k].name
else:
value = self.__dict__[k]
t += '%s: %s\r\n' % (k, value)
return t
class FD_FLAGS(enum.IntFlag):
ATTRIBUTES = 0x00000004 #The fileAttributes field contains valid data.
FILESIZE = 0x00000040 #The fileSizeHigh and fileSizeLow fields contain valid data.
WRITESTIME = 0x00000020 #The lastWriteTime field contains valid data.
SHOWPROGRESSUI = 0x00004000 #A progress indicator SHOULD be shown when copying the file.
class FILE_ATTRIBUTE(enum.IntFlag):
READONLY = 0x00000001 #A file that is read-only. Applications can read the file, but cannot write to it or delete it.
HIDDEN = 0x00000002 #The file or directory is hidden. It is not included in an ordinary directory listing.
SYSTEM = 0x00000004 #A file or directory that the operating system uses a part of, or uses exclusively.
DIRECTORY = 0x00000010 #Identifies a directory.
ARCHIVE = 0x00000020 #A file or directory that is an archive file or directory. Applications typically use this attribute to mark files for backup or removal.
NORMAL = 0x00000080 #A file that does not have other attributes set. This attribute is valid only when used alone.
class CLIPRDR_FILEDESCRIPTOR:
def __init__(self):
self.flags:FD_FLAGS = None
self.reserved1:bytes = b'\x00'*32
self.fileAttributes:FILE_ATTRIBUTE = None
self.reserved2:bytes = None
self.lastWriteTime:int = None
self.fileSizeHigh:int = None
self.fileSizeLow:int = None
self.fileName:str = None #520 bytes, 260 chars null term
self.fileSize:int =None
def to_bytes(self):
if self.fileSize is not None:
self.fileSizeHigh = self.fileSize >> 32
self.fileSizeLow = self.fileSize & 0xFFFFFFFF
t = self.flags.to_bytes(4, byteorder='little', signed=False)
t += self.reserved1
t += self.fileAttributes.to_bytes(4, byteorder='little', signed=False)
t += self.reserved2
t += self.lastWriteTime.to_bytes(8, byteorder='little', signed=False)
t += self.fileSizeHigh.to_bytes(4, byteorder='little', signed=False)
t += self.fileSizeLow.to_bytes(4, byteorder='little', signed=False)
t += self.fileName.encode('utf-16-le').ljust(b'\x00',520)
return t
@staticmethod
def from_bytes(bbuff: bytes):
return CLIPRDR_FILEDESCRIPTOR.from_buffer(io.BytesIO(bbuff))
@staticmethod
def from_buffer(buff: io.BytesIO):
msg = CLIPRDR_FILEDESCRIPTOR()
msg.flags = FD_FLAGS(int.from_bytes(buff.read(4), byteorder='little', signed=False))
msg.reserved1 = buff.read(32)
msg.fileAttributes = FILE_ATTRIBUTE(int.from_bytes(buff.read(4), byteorder='little', signed=False))
msg.reserved2 = buff.read(16)
msg.lastWriteTime = FILE_ATTRIBUTE(int.from_bytes(buff.read(8), byteorder='little', signed=False))
msg.fileSizeHigh = FILE_ATTRIBUTE(int.from_bytes(buff.read(4), byteorder='little', signed=False))
msg.fileSizeLow = FILE_ATTRIBUTE(int.from_bytes(buff.read(4), byteorder='little', signed=False))
msg.fileName = buff.read(520).decode('utf-16-le').replace('\x00','')
msg.fileSize = msg.fileSizeHigh << 32 | msg.fileSizeLow
return msg
def __repr__(self):
t = '==== CLIPRDR_FILEDESCRIPTOR ====\r\n'
for k in self.__dict__:
if isinstance(self.__dict__[k], enum.IntFlag):
value = self.__dict__[k]
elif isinstance(self.__dict__[k], enum.Enum):
value = self.__dict__[k].name
else:
value = self.__dict__[k]
t += '%s: %s\r\n' % (k, value)
return t
class CLIPRDR_FILELIST:
def __init__(self):
self.cItems:MAPPING_MODE = None
self.fileDescriptorArray:List[CLIPRDR_FILEDESCRIPTOR] = []
def to_bytes(self):
t = len(self.fileDescriptorArray).to_bytes(4, byteorder='little', signed=False)
for fd in self.fileDescriptorArray:
t += fd.to_bytes()
return t
@staticmethod
def from_bytes(bbuff: bytes):
return CLIPRDR_FILELIST.from_buffer(io.BytesIO(bbuff))
@staticmethod
def from_buffer(buff: io.BytesIO):
msg = CLIPRDR_FILELIST()
msg.cItems = int.from_bytes(buff.read(4), byteorder='little', signed=False)
for _ in range(msg.cItems):
msg.fileDescriptorArray.append(CLIPRDR_FILEDESCRIPTOR.from_buffer(buff))
return msg
def __repr__(self):
t = '==== CLIPRDR_FILELIST ====\r\n'
for k in self.__dict__:
if isinstance(self.__dict__[k], enum.IntFlag):
value = self.__dict__[k]
elif isinstance(self.__dict__[k], enum.Enum):
value = self.__dict__[k].name
else:
value = self.__dict__[k]
t += '%s: %s\r\n' % (k, value)
return t
class CLIPRDR_FORMAT_DATA_RESPONSE:
def __init__(self):
self.dataobj = None
def to_bytes(self, otype:CLIPBRD_FORMAT):
if otype == CLIPBRD_FORMAT.CF_UNICODETEXT:
t = self.dataobj.encode('utf-16-le') + b'\x00'*3
elif otype == CLIPBRD_FORMAT.CF_TEXT:
t = self.dataobj.encode('ascii') + b'\x00'
else:
t = self.dataobj.to_bytes()
return t
@staticmethod
def from_bytes(bbuff: bytes, otype:CLIPBRD_FORMAT):
return CLIPRDR_FORMAT_DATA_RESPONSE.from_buffer(io.BytesIO(bbuff), otype = otype)
@staticmethod
def from_buffer(buff: io.BytesIO, otype:CLIPBRD_FORMAT):
msg = CLIPRDR_FORMAT_DATA_RESPONSE()
if otype == CLIPBRD_FORMAT.CF_HDROP: #TODO: not sure
msg.dataobj = CLIPRDR_FILELIST.from_buffer(buff)
elif otype == CLIPBRD_FORMAT.CF_PALETTE:
msg.dataobj = CLIPRDR_PALETTE.from_buffer(buff)
elif otype == CLIPBRD_FORMAT.CF_METAFILEPICT:
msg.dataobj = CLIPRDR_MFPICT.from_buffer(buff)
elif otype == CLIPBRD_FORMAT.CF_UNICODETEXT:
msg.dataobj = buff.read().decode('utf-16-le').replace('\x00','')
elif otype == CLIPBRD_FORMAT.CF_TEXT:
msg.dataobj = buff.read().decode().replace('\x00','')
return msg
def __repr__(self):
t = '==== CLIPRDR_FORMAT_DATA_RESPONSE ====\r\n'
for k in self.__dict__:
if isinstance(self.__dict__[k], enum.IntFlag):
value = self.__dict__[k]
elif isinstance(self.__dict__[k], enum.Enum):
value = self.__dict__[k].name
else:
value = self.__dict__[k]
t += '%s: %s\r\n' % (k, value)
return t