add constant, layout, implements, properties and marshal field wrappers and Assembly table wrapper
This commit is contained in:
parent
ce9a1aefa2
commit
c823b0fc41
|
@ -142,6 +142,17 @@ class CLIFile:
|
|||
def entrypoint(self):
|
||||
return self.get_by_token(self.header.entrypoint)
|
||||
|
||||
@property
|
||||
def assembly(self):
|
||||
try:
|
||||
return self.get_table_entry(CLITableType.Assembly, 1)
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
@property
|
||||
def referenced_assemblies(self):
|
||||
return self.get_table(CLITableType.AssemblyRef)
|
||||
|
||||
@property
|
||||
def classes(self):
|
||||
return (
|
||||
|
|
|
@ -6,7 +6,7 @@ from .common import (
|
|||
CLIElementType, CLIStreamType, CLITableType,
|
||||
CLICodedToken, CLIStreamIndex, CLITableIndex, CLITableRange
|
||||
)
|
||||
from .types import CLISignature
|
||||
from .types import CLIElementType, CLISignature, CLINativeSignature
|
||||
|
||||
|
||||
TABLE_PARSERS = {}
|
||||
|
@ -240,11 +240,20 @@ CustomAttributeType = CLICodedToken([
|
|||
None, None, CLITableType.MethodDef, CLITableType.MemberRef, None
|
||||
])
|
||||
|
||||
class CLICustomAttribute(Struct, nocopy=True):
|
||||
prolog = Sig(b'\x01\x00')
|
||||
fixed = Arr([])
|
||||
named_count = UInt(16)
|
||||
named = Arr([])
|
||||
|
||||
def on_named_count(self, spec, context):
|
||||
spec.named.count = self.named_count
|
||||
|
||||
@table_parser(CLITableType.CustomAttribute)
|
||||
class CLICustomAttributeTable(Struct, nocopy=True):
|
||||
parent = HasCustomAttribute
|
||||
type = CustomAttributeType
|
||||
value = CLIStreamIndex(CLIStreamType.Blob)
|
||||
value = CLIStreamIndex(CLIStreamType.Blob, CLICustomAttribute)
|
||||
|
||||
|
||||
@table_parser(CLITableType.StandAloneSig)
|
||||
|
@ -354,7 +363,7 @@ HasConstant = CLICodedToken([
|
|||
|
||||
@table_parser(CLITableType.Constant)
|
||||
class CLIConstantTable(Struct, nocopy=True):
|
||||
type = UInt(8)
|
||||
type = Enum(CLIElementType, UInt(8))
|
||||
_pad1 = UInt(8)
|
||||
parent = HasConstant
|
||||
value = CLIStreamIndex(CLIStreamType.Blob)
|
||||
|
@ -534,7 +543,7 @@ HasFieldMarshal = CLICodedToken([CLITableType.Field, CLITableType.Param])
|
|||
@table_parser(CLITableType.FieldMarshal)
|
||||
class CLIFieldMarshalTable(Struct, nocopy=True):
|
||||
parent = HasFieldMarshal
|
||||
native_type = CLIStreamIndex(CLIStreamType.Blob)
|
||||
native_type = CLIStreamIndex(CLIStreamType.Blob, CLINativeSignature)
|
||||
|
||||
|
||||
@table_parser(CLITableType.EncLog)
|
||||
|
|
108
dotnet/types.py
108
dotnet/types.py
|
@ -6,6 +6,88 @@ from .util import MultiEnum
|
|||
from .common import CLICodedToken, CLITableType, CLIElementType
|
||||
|
||||
|
||||
class CLICompressedInt(Type):
|
||||
def __init__(self, signed=True):
|
||||
self.signed = signed
|
||||
|
||||
def parse(self, input, context):
|
||||
val = input.read(1)[0]
|
||||
if (val >> 5) == 0b110:
|
||||
nbytes = 4
|
||||
b = bytearray([val & 0b11111])
|
||||
elif (val >> 6) == 0b10:
|
||||
nbytes = 2
|
||||
b = bytearray([val & 0b111111])
|
||||
else:
|
||||
nbytes = 1
|
||||
b = bytearray([val])
|
||||
b.extend(input.read(nbytes - 1))
|
||||
return int.from_bytes(b, byteorder='big', signed=self.signed)
|
||||
|
||||
class CLICompressedUInt(Type):
|
||||
def __new__(self):
|
||||
return CLICompressedInt(signed=False)
|
||||
|
||||
|
||||
class CLINativeElementType(enum.Enum):
|
||||
Boolean = 0x2
|
||||
I1 = 0x3
|
||||
U1 = 0x4
|
||||
I2 = 0x5
|
||||
U2 = 0x6
|
||||
I4 = 0x7
|
||||
U4 = 0x8
|
||||
I8 = 0x9
|
||||
U8 = 0xA
|
||||
R4 = 0xB
|
||||
R8 = 0xC
|
||||
LPStr = 0x14
|
||||
LPWStr = 0x15
|
||||
Int = 0x1F
|
||||
UInt = 0x20
|
||||
Function = 0x26
|
||||
Array = 0x2A
|
||||
|
||||
class CLINativeType:
|
||||
pass
|
||||
|
||||
class CLINativeIntrinsicType(CLINativeType):
|
||||
def __init__(self, type: CLIElementType):
|
||||
self.type = type
|
||||
|
||||
def __str__(self):
|
||||
return self.type.name.lower()
|
||||
|
||||
def __repr__(self):
|
||||
return '<{}: {}>'.format(self.__class__.__name__, self.type.name)
|
||||
|
||||
class CLINativeArrayType(CLINativeType):
|
||||
def __init__(self, type, count, count_param):
|
||||
self.type = type
|
||||
self.count = count
|
||||
self.count_param = count_param
|
||||
|
||||
def __str__(self):
|
||||
return str(self.type) + '[{}]'.format(self.count if self.count is not None else '')
|
||||
|
||||
def __repr__(self):
|
||||
return '<{}: {}[{}] @ {}>'.format(
|
||||
self.__class__.__name__, self.type.name,
|
||||
self.count if self.count is not None else '', self.count_param
|
||||
)
|
||||
|
||||
class CLINativeSignature(Struct, nocopy=True):
|
||||
type = Enum(CLINativeElementType, CLICompressedUInt())
|
||||
elem_type = Maybe(Enum(CLINativeElementType, CLICompressedUInt()))
|
||||
count_param = Maybe(CLICompressedUInt())
|
||||
count = Maybe(CLICompressedUInt())
|
||||
|
||||
def parse(self, input, context):
|
||||
val = super().parse(input, context)
|
||||
if val.type == CLINativeElementType.Array:
|
||||
return CLINativeArrayType(val.elem_type, val.count, val.count_param)
|
||||
return CLINativeIntrinsicType(val.type)
|
||||
|
||||
|
||||
class CLIType:
|
||||
pass
|
||||
|
@ -18,7 +100,7 @@ class CLIPrimitiveType(CLIType):
|
|||
return self.type.name.lower()
|
||||
|
||||
def __repr__(self):
|
||||
return '<{}: {}>'.format(self.__class__.__name__, self.type.value)
|
||||
return '<{}: {}>'.format(self.__class__.__name__, self.type.name)
|
||||
|
||||
class CLIPointerType(CLIType):
|
||||
def __init__(self, child: CLIType):
|
||||
|
@ -189,28 +271,6 @@ class CLIElement(Type):
|
|||
return val
|
||||
|
||||
|
||||
class CLICompressedInt(Type):
|
||||
def __init__(self, signed=True):
|
||||
self.signed = signed
|
||||
|
||||
def parse(self, input, context):
|
||||
val = input.read(1)[0]
|
||||
if (val >> 5) == 0b110:
|
||||
nbytes = 4
|
||||
b = bytearray([val & 0b11111])
|
||||
elif (val >> 6) == 0b10:
|
||||
nbytes = 2
|
||||
b = bytearray([val & 0b111111])
|
||||
else:
|
||||
nbytes = 1
|
||||
b = bytearray([val])
|
||||
b.extend(input.read(nbytes - 1))
|
||||
return int.from_bytes(b, byteorder='big', signed=self.signed)
|
||||
|
||||
class CLICompressedUInt(Type):
|
||||
def __new__(self):
|
||||
return CLICompressedInt(signed=False)
|
||||
|
||||
class CLISignatureType(enum.Enum):
|
||||
Default = 0x0
|
||||
C = 0x1
|
||||
|
@ -257,7 +317,7 @@ class CLIPropertySignature(Struct, nocopy=True):
|
|||
spec.params.count = self.param_count
|
||||
|
||||
def __str__(self):
|
||||
return '(' + ', '.join(str(p) for p in self.params) + ') -> ' + str(self.ret_type)
|
||||
return '(' + ', '.join(str(p) for p in self.params) + ') -> ' + str(self.type)
|
||||
|
||||
class CLILocalVarSignature(Struct, nocopy=True):
|
||||
count = CLICompressedUInt()
|
||||
|
|
|
@ -132,8 +132,34 @@ class CLITypeRef(CLITableWrapper):
|
|||
namespace = self.namespace
|
||||
return '<{}: {}{} (from {})>'.format(self.__class__.__name__, namespace + '.' if namespace else '', self.name, self.scope.name)
|
||||
|
||||
@register_wrapper(CLITableType.Property)
|
||||
class CLIProperty(CLITableWrapper):
|
||||
@cached_property
|
||||
def constant(self):
|
||||
try:
|
||||
return next(c for c in self._file.get_table(CLITableType.Constant) if c.parent == self)
|
||||
except StopIteration:
|
||||
return None
|
||||
|
||||
def __repr__(self):
|
||||
return '<{}: {} {}>'.format(self.__class__.__name__, self.signature, self.name)
|
||||
|
||||
@register_wrapper(CLITableType.Param)
|
||||
class CLIParam(CLITableWrapper):
|
||||
@cached_property
|
||||
def marshal(self):
|
||||
try:
|
||||
return next(l for l in self._file.get_table(CLITableType.FieldMarshal) if l.parent == self)
|
||||
except StopIteration:
|
||||
return None
|
||||
|
||||
@cached_property
|
||||
def constant(self):
|
||||
try:
|
||||
return next(c for c in self._file.get_table(CLITableType.Constant) if c.parent == self)
|
||||
except StopIteration:
|
||||
return None
|
||||
|
||||
def __repr__(self):
|
||||
return '<{} ({}): {}>'.format(self.__class__.__name__, self.sequence, self.name)
|
||||
|
||||
|
@ -143,6 +169,27 @@ class CLIField(CLITableWrapper):
|
|||
def parent(self):
|
||||
return next(c for c in self._file.classes if self in c.fields)
|
||||
|
||||
@cached_property
|
||||
def layout(self):
|
||||
try:
|
||||
return next(l for l in self._file.get_table(CLITableType.FieldLayout) if l.field == self)
|
||||
except StopIteration:
|
||||
return None
|
||||
|
||||
@cached_property
|
||||
def marshal(self):
|
||||
try:
|
||||
return next(l for l in self._file.get_table(CLITableType.FieldMarshal) if l.parent == self)
|
||||
except StopIteration:
|
||||
return None
|
||||
|
||||
@cached_property
|
||||
def constant(self):
|
||||
try:
|
||||
return next(c for c in self._file.get_table(CLITableType.Constant) if c.parent == self)
|
||||
except StopIteration:
|
||||
return None
|
||||
|
||||
def __repr__(self):
|
||||
return '<{}: {} {}>'.format(self.__class__.__name__, self.signature, self.name)
|
||||
|
||||
|
@ -172,8 +219,35 @@ class CLIClass(CLITableWrapper):
|
|||
|
||||
@cached_property
|
||||
def children(self):
|
||||
return [c.nested for c in self._file.get_table(CLITableType.NestedClass) if c.enclosing == self]
|
||||
return (c.nested for c in self._file.get_table(CLITableType.NestedClass) if c.enclosing == self)
|
||||
|
||||
@cached_property
|
||||
def layout(self):
|
||||
try:
|
||||
return next(l for l in self._file.get_table(CLITableType.ClassLayout) if l.parent == self)
|
||||
except StopIteration:
|
||||
return None
|
||||
|
||||
@property
|
||||
def implements(self):
|
||||
return (i.interface for i in self._file.get_table(CLITableType.InterfaceImpl) if i.type == self)
|
||||
|
||||
@property
|
||||
def properties(self):
|
||||
try:
|
||||
return next(p.properties for p in self._file.get_table(CLITableType.PropertyMap) if p.parent == self)
|
||||
except StopIteration:
|
||||
return []
|
||||
|
||||
def __repr__(self):
|
||||
namespace = self.namespace
|
||||
return '<{}: {}{}>'.format(self.__class__.__name__, namespace + '.' if namespace else '', self.name)
|
||||
|
||||
@register_wrapper(CLITableType.Assembly)
|
||||
@register_wrapper(CLITableType.AssemblyRef)
|
||||
class CLIAssembly(CLITableWrapper):
|
||||
def __repr__(self):
|
||||
return '<{}: {} (v{}.{}.{}.{})>'.format(
|
||||
self.__class__.__name__, self.name,
|
||||
self.version_major, self.version_minor, self.build_number, self.rev_number
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue